pax_global_header00006660000000000000000000000064144603410020014504gustar00rootroot0000000000000052 comment=fe8c421fd0977c21c47de2ba4630952dc47fd47b repowerd-2023.07/000077500000000000000000000000001446034100200135105ustar00rootroot00000000000000repowerd-2023.07/AUTHORS000066400000000000000000000003431446034100200145600ustar00rootroot00000000000000Alexander Martinz Alexandros Frantzis Alfred Neumayer Dalton Durst Erfan Abdi Florian Leeber Guido Berhoerster Jami Kettunen Katharine Chui Luca Weiss Marius Gripsgard Michał Sawicz Mike Gabriel Ratchanan Srirattanamet Rodney repowerd-2023.07/CMakeLists.txt000066400000000000000000000074271446034100200162620ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis project(repowerd) set(REPOWERD_VERSION "2023.07") cmake_minimum_required(VERSION 3.0) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) option(REPOWERD_BUILD_TESTS "Build tests" ON) option(REPOWERD_DISABLE_TIME_SENSITIVE_TESTS "Don't run time-sensitive tests" OFF) option(REPOWERD_ENABLE_HYBRIS "Enable hybris support" ON) option(REPOWERD_ENABLE_BINDER "Enable binder support" ON) # Work around cmake setting conf dir to "/usr/etc" instead of "/etc" # when prefix is "/usr" if (NOT DEFINED CMAKE_INSTALL_SYSCONFDIR AND CMAKE_INSTALL_PREFIX STREQUAL "/usr") set(CMAKE_INSTALL_SYSCONFDIR "/etc") endif() enable_testing() include(GNUInstallDirs) find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(DEVICEINFO REQUIRED deviceinfo) pkg_check_modules(GIO REQUIRED gio-2.0) pkg_check_modules(GIO_UNIX REQUIRED gio-unix-2.0) if (REPOWERD_ENABLE_HYBRIS) pkg_check_modules(UA REQUIRED ubuntu-platform-api) pkg_check_modules(LIBHARDWARE REQUIRED libhardware) pkg_check_modules(UBUNTU_PLATFORM_HARDWARE_API REQUIRED ubuntu-platform-hardware-api) find_package(AndroidHeaders REQUIRED) endif() if (REPOWERD_ENABLE_BINDER) pkg_check_modules(GBINDER REQUIRED libgbinder) endif() set(build_types "None;Debug;Release;RelWithDebInfo;MinSizeRel;AddressSanitizer;ThreadSanitizer") # Change informational string for CMAKE_BUILD_TYPE set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "${build_types}" FORCE) # Enable cmake-gui to display a drop down list for CMAKE_BUILD_TYPE set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${build_types}") set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pthread -std=c11 -Werror -Wall -Wextra -pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -pthread -std=c++14 -Werror -Wall -Wnon-virtual-dtor -Wextra -pedantic") string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower) if(cmake_build_type_lower MATCHES "addresssanitizer") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") elseif(cmake_build_type_lower MATCHES "threadsanitizer") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=thread") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") link_libraries(tsan) # Workaround for LP:1413474 endif() set(POWERD_DEVICE_CONFIG_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/powerd/device_configs") set(REPOWERD_DEVICE_CONFIG_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/repowerd/device-configs") add_definitions(-DREPOWERD_VERSION="${REPOWERD_VERSION}") add_subdirectory(src/) add_subdirectory(data/) if(REPOWERD_BUILD_TESTS) find_package(GMock REQUIRED) add_subdirectory(tests/) endif() repowerd-2023.07/ChangeLog000066400000000000000000001164321446034100200152710ustar00rootroot000000000000002023-07-27 Marius Gripsgard * Release 2023.07 (HEAD -> main, tag: 2023.07) * Add more missing headers for gcc 13 (5e125ca) 2023-06-08 Mike Gabriel * Merge branch 'headers' into 'main' (7559c26) 2023-06-07 Luca Weiss * Add missing headers for GCC13 (903b227) 2023-04-21 Mike Gabriel * Merge branch 'listSysRequests' into 'main' (d4368a0) 2023-04-01 Katharine Chui * support listing keep display on and notification requests on the interface (13b8c49) 2023-03-31 Katharine Chui * unity_screen_service: implement com.lomiri.Repowerd.listSysRequests() (f76a473) 2023-04-08 Marius Gripsgard * Merge branch 'personal/peat-psuwit/sensorfw-fixes' into 'main' (24d9f03) 2023-03-11 Ratchanan Srirattanamet * socketreader: correct isConnected() logic inversion (b26571b) * socketreader: log error and handle EOF more gracefully (06067ac) * sensorfw_common: clean up after itself if it fails to start (16c18bf) 2023-03-10 Ratchanan Srirattanamet * utils/socketreader: fix integer overflow in skipAll() (9a1129a) 2023-03-09 Ratchanan Srirattanamet * sensorfw/common: don't leak pluginPath (228d66a) 2023-04-04 Ratchanan Srirattanamet * Merge branch 'nullptr-mClient' into 'main' (8c72375) 2023-04-04 Jami Kettunen * BinderPerformanceBooster: Guarantee mRemote init before mClient (11a98b2) 2023-04-03 Jami Kettunen * BinderPerformanceBooster: Initialize new private vars as nullptr (041de9e) 2023-03-31 Marius Gripsgard * Merge branch 'personal/fredldotme/powerhal' into 'main' (d96d1a5) 2023-03-27 Alfred Neumayer * BinderPerformanceBooster: Set proper data parameter when calling PowerHAL PowerHint feature (b2fbc06) 2023-03-18 Alfred Neumayer * binder_performance_booster: Plug memory leak and nullptr check for Halium 7.1 (1041610) * binder_performance_booster: PowerHints & PowerScene support (4b5e3af) 2023-02-25 Alfred Neumayer * debian: Enable Binder-based PowerHAL booster (272bf07) * src: Implement PowerHAL integration (2fbc1e1) 2023-03-16 Ratchanan Srirattanamet * Merge branch 'screenBrightnessBacklight' into 'main' (062ef8e) 2023-03-13 Katharine Chui * adapter: add comments regarding the usage of screenBrightnessBacklight (bf8b7dc) 2022-07-01 Alfred Neumayer * adapters: Fix Autobrightness exception logging (aebee4d) 2021-03-19 Marius Gripsgard * Adapters: Make sure to log why we failed to create brightness spline (68a88ad) 2020-05-28 Erfan Abdi * [DNM] Add android 9 overlays auto brightness support (df75fe5) 2023-03-16 Mike Gabriel * Merge branch 'personal/peat-psuwit/sensorfw-light-skip-bogus' into 'main' (63248fc) 2023-03-14 Ratchanan Srirattanamet * SensorfwLightSensor: skip bogus value of 0 (b602097) Fixes: https://gitlab.com/ubports/development/core/repowerd/-/issues/38 2023-03-15 Mike Gabriel * Merge branch 'personal/gberh/log-levels' into 'main' (9e5225a) 2023-03-14 Guido Berhoerster * Make log level threshold configurable and set default (918f9de) * Make use of log levels (0438fcf) * Add log levels to logger (904f6fb) 2023-02-26 Mike Gabriel * Merge branch 'focal-proper-backlight-ctrl' into 'main' (32605e4) 2022-03-23 Florian Leeber * Try to improve dimming durations (90eae65) 2023-02-17 Mike Gabriel * Merge branch 'personal/sunweaver/log-suspend-blocker-id' into 'main' (bd7a5d4) 2021-07-15 Dalton Durst * Log the suspend blocker ID in DefaultStateMachine (e304aa8) 2023-02-15 Mike Gabriel * Merge branch 'gmock-usage' into 'main' (d4632a3) 2022-08-02 Luca Weiss * Fix GMock library target usage (4d1a97e) 2022-12-15 Marius Gripsgard * Merge branch 'personal/gberh/add-envfile' into 'main' (fb27f3b) 2022-12-15 Guido Berhoerster * Add example environment file read by the systemd service file (b999c49) 2022-12-13 Mike Gabriel * Merge branch 'personal/fredldotme/sargofp4brightness' into 'main' (20d4ba9) 2022-12-13 Alfred Neumayer * adapters: sensorfw: Adjust DBus timeouts a bit (29e7228) 2022-07-01 Alfred Neumayer * adapters: Loosen sensorfw timeouts a bit (851ec1e) 2022-12-02 Mike Gabriel * Merge branch 'personal/fredldotme/sargosplines' into 'main' (14e02fb) 2021-08-12 Alfred Neumayer * autobrightness: Fix creating spline points with 255 values (1bbbd7d) 2022-11-22 Mike Gabriel * Merge branch 'sunweaver/personal/system-unit-with-cmake' into 'main' (542c458) * debian/control: Add to B-D: systemd. (aba01c6) 2020-08-14 Marius Gripsgard * Install systemd unit with cmake not just debian pkg (5d893cb) 2022-11-16 Mike Gabriel * Merge branch 'personal/peat-psuwit/sensorfw-proper' into 'main' (8accb8e) 2022-11-11 Ratchanan Srirattanamet * debian/repowerd.service: add deps on dbus.socket and sensorfwd (882b1c8) 2020-04-04 Marius Gripsgard * [adapters] Implement sensorfw light and proximity adapters (18d87bb) 2022-08-15 Ratchanan Srirattanamet * Merge branch 'systemd-migration' into 'main' (0a01a97) 2022-08-15 Guido Berhoerster * Remove unused upstart job (656ad47) 2022-08-01 Marius Gripsgard * Merge branch 'mr/typo-fix' into 'main' (75048fc) 2022-07-13 Marius Gripsgard * Merge branch 'main-dt2w' into 'main' (d6dcb7e) 2022-03-15 Alexander Martinz * Introduce support for Double Tap To Wake (DT2W) (5c1863a) 2022-05-31 Ratchanan Srirattanamet * Merge branch 'personal/mariogrip/focal_-_deviceinfo' into 'main' (67a5e59) 2020-01-19 Marius Gripsgard * Replace libandroid-properties with libdeviceinfo (e963bc4) 2022-02-16 Mike Gabriel * src/adapters/unity_screen_service.cpp: Typo fix. (5ec81f6) 2022-02-02 Mike Gabriel * Release 2022.01 (c9637e9) (tag: 2022.01) 2021-12-01 Marius Gripsgard * Merge branch 'personal/peat-psuwit/merge-xenial-2021Nov' into 'main' (810c7d1) 2021-11-29 Ratchanan Srirattanamet * Merge remote-tracking branch 'gitlab_ubports/ubports/xenial' into personal/peat-psuwit/merge-xenial-2021Nov (097638b) 2021-08-12 Florian Leeber * Merge branch 'personal/usb/suspend-delay-3' into 'ubports/xenial' (69e3ead) 2021-08-11 Dalton Durst * default_state_machine: 4 second delay before suspend (7ce336d) 2021-07-20 Dalton Durst * Merge branch 'personal/peat-psuwit/rename-to-lomiri' into 'main' (481457c) 2021-06-30 Dalton Durst * Merge branch 'personal/peat-psuwit/fix-gh-ut-1747' into 'ubports/xenial' (a566d2c) 2021-06-30 Ratchanan Srirattanamet * default_daemon_config: actually return created UbuntuLightSensor (ee41141) Fixes: https://github.com/ubports/ubuntu-touch/issues/1747 2021-06-04 Ratchanan Srirattanamet * CMakeLists: bump version to match d/changelog (dbf8e0c) * d/{control,rules}: accommodate cmake-extras migration & no platform-api (650abde) * d/repowerd.service: update bus name (81e84e9) * Rename com.canonical.powerd to com.lomiri.Repowerd (8a6500d) * Rename com.canonical.repowerd to com.lomiri.Repowerd.Settings (d87b9a0) 2021-05-29 Ratchanan Srirattanamet * src, tests: rename interfaces to lomiri-system-compositor (f453e89) 2021-05-28 Ratchanan Srirattanamet * event_loop: ignore function casting -Werror (ff24112) * tests: make sure we don't include gtest_main needlessly (f606f47) * CMakeLists: migrate to FindGMock from cmake-extras (36af0bf) 2021-06-10 Dalton Durst * Merge branch 'xenial_-_build-without-hybris' into 'ubports/xenial' (5b22003) 2021-06-04 Ratchanan Srirattanamet * Move Jenkinsfile to debian/ per the new guideline (c4dd9f0) * Update Jenkinsfile to use shared library (6b9d4fc) 2021-05-28 Ratchanan Srirattanamet * tests/adapter-tests: fix building without hybris/platform-api (6a10bc4) * default_daemon_config: add missing includes for non-hybris case (ea86e35) 2021-03-25 Marius Gripsgard * Merge pull request #17 from ubports/xenial_-_wayland-session (1375dd3) 2021-03-24 Marius Gripsgard * Merge pull request #20 from ubports/xenial_-_clock-alarm (0424d9b) 2021-03-15 Rodney * Merge pull request #16 from ubports/xenial_-_missing-header (1f5a30e) 2020-05-27 Marius Gripsgard * adapters: timerfd: Implement CLOCK_REALTIME_ALARM (1576f3c) 2020-08-14 Marius Gripsgard * adapters: logind: Make wayland session a compatable repowerd session (5b3b74b) 2021-01-14 Marius Gripsgard * Allow to be built without hybris/android/papi support (fc4bc9b) * core: Add missing header (025e510) 2020-09-08 Ratchanan Srirattanamet * core: do disallow automatic suspend on client request (5c9e029) 2020-08-12 Marius Gripsgard * Merge pull request #10 from ubports/xenial_-_fix-proximity-hiccup (2a0e480) 2020-07-18 Florian Leeber * The Oneplus One also needs to have the initial fake event reversed (08419b8) 2020-06-24 Ratchanan Srirattanamet * core: actually uses suspend inhibitions in automatic suspend decision (946c666) 2020-05-05 Ratchanan Srirattanamet * debian: uses a link instead of a file copy for powerd compat config (04dce2e) 2020-05-04 Ratchanan Srirattanamet * Revert "core: Suspend inhibitions should affect automatic suspend only when display turns off due to inactivity" (cfb1cec) * Update Jenkinsfile as of ubports/build-tools@10c0987 (955732c) 2020-04-08 Marius Gripsgard * Update changelog (36c10ca) 2020-01-22 Florian Leeber * Use default config from other directory (#7) (ec4223e) 2018-10-25 Alfred Neumayer * adapters: Fix crash in UPowerPowerSource's critical temperature assignment Using std::stod when parsing UPower's shutdownBatteryTemperature setting causes repowerd to crash on Sony Xperia X (arm64 kernel). Use std::stoi instead as the setting itself is backed by an integer type in UPower itself. (4d3f54c) 2018-01-15 Marius Gripsgard * Import to ubp (a6362f4) 2017-12-17 Marius Gripsgard * Always set brightness before first autobrightness setting fixes https://github.com/ubports/ubuntu-touch/issues/305 (cd09c43) 2018-01-15 Marius Gripsgard * Add Jenkinsfile (ad3225c) 2017-04-03 Bileto Bot * Releasing 2017.03+17.04.20170403-0ubuntu1 (9d02adb) 2017-04-03 Alexandros Frantzis * 2017.03 release - Fix "Closing the lid does not suspend the device" (LP: #1668596) - Fix "messages are logged on every input event" (LP: #1674736) - Fix brightness issues when turning on the screen on Fairphone 2 - Add apport hook (69cb91e) * adapters: Fix UnityDisplay::turn_on memory leak (f498d04) 2017-03-29 Alexandros Frantzis * Prepare files for 2017.03 release (69d9e6a) 2017-03-28 Alexandros Frantzis * debian: Add apport hook (36fabb4) * adapters: Ensure dimming a lit display will not increase its brightness (56c2aa8) * adapters: Fix application of user-set normal brightness value (d433783) * tests: Make rt::FakeTimer thread-safe to avoid races in tests (230ccf5) 2017-03-27 Alexandros Frantzis * adapters: Implement system suspend block notifications for LogindSystemPowerControl (140ec67) * core: Introduce system suspend block infrastructure and core logic (e438a1b) * core: Suspend inhibitions should affect automatic suspend only when display turns off due to inactivity (8fd9f6b) 2017-03-23 Alexandros Frantzis * core: Ensure we don't suspend the system when session is inactive (b565779) * core,adapters: Refactor SystemPowerControl::(dis)allow_suspend() methods (87db540) * core,adapters: Remove obsolete SystemPowerControl methods (deb4948) * core: Implement suspend disallowance logic in DefaultStateMachine (2575366) * core,adapters: Move suspend dis/allowance handling to the per-session state machine (05976cf) * adapters: Don't inhibit logind suspends for suspend block requests sent to repowerd (7379903) * core: Suspend action when closing lid should not respect suspend inhibitions (2b15a62) * tests: Add test for UnityDisplay::turn_on() maximum wait (2081084) 2017-03-18 Ratchanan Srirattanamet * adapters: make the screen-on call to u-s-c synchronous (49761c8) 2017-03-22 Alexandros Frantzis * tests: Deduplicate duration_of() helper function (4bda546) * debian: Don't log to /var/log/syslog (de8282f) 2017-02-21 Bileto Bot * Releasing 2017.02+17.04.20170221-0ubuntu1 (f7263a9) 2017-02-21 Alexandros Frantzis * Prepare files for 2017.02 release (83ac5f3) * adapters: Generate random cookies for wakeup requests (3510a46) 2017-02-20 Alexandros Frantzis * tests: Fix destruction order of test object members (0a94520) 2017-02-17 Alexandros Frantzis * adapters: Add missing signal from Unity.Screen introspection (926f1ed) * doc: Add com.canonical.repowerd DBus API documentation (4be1095) 2017-02-15 Alexandros Frantzis * tests: Add REPOWERD_TEST_LOG environment variable (00ce88f) * adapters: Improve critical battery behavior (e978612) 2017-02-14 Alexandros Frantzis * adapters: Refactor upower based power source to use DisplayDevice (db0b761) * tools: Add settings support to repowerd-cli (a5b6ab7) 2017-02-13 Alexandros Frantzis * adapters: Implement dbus based client settings (4cfb8f7) 2017-02-14 Alexandros Frantzis * core: Apply changes to inactivity timeouts when the power source changes (b55da16) * core: Don't accept the display-off action for the lid behavior setting (a2e2693) 2017-02-09 Alexandros Frantzis * core: Add core logic for critical power behavior setting (ac81a3a) * core: Add critical power behavior support in ClientSettings and hook it up in the daemon (22637fd) 2017-02-08 Alexandros Frantzis * core: Add core logic for lid behavior settings (188dba8) * core: Add lid behavior support in ClientSettings and hook it up in the daemon (6a1205f) * adapters: Implement logind based system resume notification (8a9410d) * core: Add system resume handling (d897dfe) 2017-01-31 Alexandros Frantzis * core: Add basic inactivity suspend timeout support (756e2fd) * tests: Update suspend expectation methods (cf3167f) 2017-01-30 Alexandros Frantzis * core,adapters: Add support for battery vs line-power client settings (8dcfd6b) 2017-01-27 Alexandros Frantzis * core: Introduce ClientSettings (5407b28) 2017-01-26 Alexandros Frantzis * core: Introduce StateMachine::handle_set_inactivity_behavior() (137b47f) 2017-02-01 Alexandros Frantzis * adapters: Implement and use TimerfdWakeupService (ebbff23) 2017-01-17 Alexandros Frantzis * core: Improve display handling during lid manipulation (2e9ada7) 2017-01-13 Alexandros Frantzis * core,adapters: Update DisplayPowerControl interface to support filters (ef55d92) * adapters: Rename UnityDisplayPowerControl to UnityDisplay (15346a2) * adapters: Implement DisplayConfiguration with UnityDisplayPowerControl (0d43e06) 2017-01-12 Alexandros Frantzis * core: Add DisplayInformation interface and core logic (433f06d) 2017-01-05 Alexandros Frantzis * adapters: Set the names of all event loop threads (956b449) 2017-01-04 Alexandros Frantzis * core,adapters: Suspend when allowed with lid closed (8f901e8) 2016-12-12 Bileto Bot * Releasing 2016.12+17.04.20161212.1-0ubuntu1 (28c65b0) 2016-12-12 Alexandros Frantzis * Prepare files for 2016.12 release (4ed91aa) 2016-12-07 Alexandros Frantzis * adapters: Temporarily disallow suspend after a power source change (56e524b) * adapters: Temporarily inhibit suspend after a hardware alarm is triggered (62ea426) * adapters: Introduce TemporarySuspendInhibition and implementation (2cb7454) * adapters: Increase synthetic proximity event delay for mako (c879a68) 2016-12-06 Alexandros Frantzis * adapters: Use a sensible time value in the future when not needing /dev/alarm (537ea5c) 2016-12-07 Alexandros Frantzis * adapters: Notify about power source changes involving the "pending charge" battery state (638bc74) 2016-12-12 Alexandros Frantzis * repowerd: Add REPOWERD_DEVICE_CONFIG_DIR environment variable (1c39d81) 2016-12-09 Alexandros Frantzis * adapters: Use proper DBus path for dbus manager (91513a1) 2016-12-05 Alexandros Frantzis * tests: Fix build with clang (a9c0985) 2016-12-02 Alexandros Frantzis * adapters: Inhibit lid handling when disallowing default logind system handlers (ef10585) 2016-11-23 Alexandros Frantzis * adapters: Rename UPowerPowerSource to UPowerPowerSourceAndLid (0640162) * adapters: Implement and use upower-based Lid (d93f52e) 2016-12-02 Alexandros Frantzis * adapters: Implement LogindSystemPowerControl::suspend_if_allowed() (153811b) 2016-11-22 Alexandros Frantzis * core: Add lid state machine logic (0686f6f) 2016-11-21 Alexandros Frantzis * core: Add Lid interface and hook it up in the daemon (95717ce) 2016-12-02 Alexandros Frantzis * core: Fix HandlerRegistration move semantics (c1d81fa) 2016-11-30 Alexandros Frantzis * adapters: Log DefaultStateMachine options (0b0a86c) * core,adapters: Add treat_power_button_as_user_activity option (3af72b2) * tests: Refactor ATurnOnDisplayAtStartupOption test (0fda3aa) * core,adapters: Move turn_on_display_at_startup option into StateMachineOptions (b8a0707) * core,adapters: Move state machine timeout options to StateMachineOptions (c78dfd6) 2016-12-01 Alexandros Frantzis * tests: Fix race in BacklightBrightnessControl tests (4883dca) * tests: Fix race in LogindSystemPowerControl tests (88e57ba) 2016-11-30 Alexandros Frantzis * adapters: Fix build with g++-4.9 and clang (48d7a81) 2016-11-29 Alexandros Frantzis * adapters: Implement LogindSystemPowerControl::(dis)allow_default_system_handlers (388e916) 2016-11-28 Alexandros Frantzis * core: Add SystemPowerControl::(dis)allow_default_system_handlers() (77dd443) * core: Add StateMachine::start() method (e1f2019) 2016-11-29 Alexandros Frantzis * core,adapters: Distinguish different suspend types and deal with them accordingly (99f74bc) 2016-11-25 Alexandros Frantzis * adapters: Add and use LogindSystemPowerControl (f78f76c) * adapters: Add repowerd::Fd move semantics support (0396aa3) * core,adapters: Merge ShutdownControl into SystemPowerControl (b1447d5) * core: Rename SuspendControl to SystemPowerControl (df83d92) 2016-11-29 Alexandros Frantzis * core: Pause active session before removing it (0d52e08) 2016-11-24 Bileto Bot * Releasing 2016.11+17.04.20161124-0ubuntu1 (9334bde) 2016-11-24 Alexandros Frantzis * tests: Add repowerd::Daemon tests for pause and resume (874bf2f) * cmake: Update FindGtestGmock.cmake for gtest/gmock 1.8.0 compatibility (ce97efd) 2016-11-16 Alexandros Frantzis * Prepare files for 2016.11 release (5e4cf24) * debian: Start by default on desktop systemd-based systems (5658501) * adapters: Accept requests without a matching session that originate from root or the active session user (3f8dab8) 2016-11-15 Alexandros Frantzis * adapters: Add ignore_session_deactivation quirk (bd445ad) 2016-11-10 Alexandros Frantzis * core: Support pausing and resuming state machines during session switches (0b6b3ec) 2016-11-11 Alexandros Frantzis * core: Update the active session when the active session is removed (97bb2d3) 2016-11-10 Alexandros Frantzis * core: Add override to NullStateMachine (7ab0b57) * tests: Use namespace testing globally in Daemon tests (efc4a07) * core: Start processing session tracking events before any per-session events (051ed29) 2016-11-09 Alexandros Frantzis * adapters: Use the logind session id (instead of the logind path) for the repowerd session id (1134a79) * core: Give each state machine a name and log it (ca1a15c) 2016-11-08 Alexandros Frantzis * core,adapters: Dispatch client requests to sessions that own them (a2b88ff) * core: Move brightness handling into state machine (ed5f6c8) * core: Daemon enqueue_action_to_active_session (1fe931c) 2016-11-03 Alexandros Frantzis * core,adapters: Introduce and use repowerd::invalid_session_id (225ff26) * core: Introduce session handling (432ea06) 2016-11-02 Alexandros Frantzis * core: Add and use StateMachineFactory (38230c4) * tools: Add repowerd-session-tool (48abb04) 2016-11-01 Alexandros Frantzis * core: Add DaemonConfig::the_session_tracker() and default implementation (805c80d) * core,adapters: Add logind-based session tracker (9814d67) 2016-10-27 Alexandros Frantzis * core,adapters: Move handling of multiple notifications from adapters to core (11fa44f) 2016-10-26 Alexandros Frantzis * core: Use a state event adapter instead of changing the state machine interface (6d588c6) * core,adapters: Move handling of multiple inactivity requests from adapters to core (913ca3f) 2016-10-25 Alexandros Frantzis * core: Don't expose underlying AlarmId type (04a0019) 2016-10-07 Bileto Bot * Releasing 2016.10+16.10.20161007-0ubuntu1 (768279e) 2016-10-07 Alexandros Frantzis * 2016.10 release (93f7646) * Prepare files for 2016.10 release (55341f9) * debian: Sync with released package (dee78d6) 2016-10-06 Alexandros Frantzis * debian: Wait for the repowerd DBus API to be accessible before declaring the upstart job as started (9096f69) * tools: Handle SIGTERM gracefully in repowerd-cli (061d484) * tools: Update repowerd-cli help text (fff9535) 2016-09-22 Alexandros Frantzis * adapters: Fix typo in brightness config value (1e8d162) 2016-08-30 Alexandros Frantzis * Prepare for 2016.08.3 release (b9fa947) * core: Enforce an upper limit to the amount of time notifications can keep the display on (c259fa7) * tools: Support the "active" command in repowerd-cli (450c1d0) 2016-08-24 Alexandros Frantzis * Sync with released version (d5020cc) 2016-08-23 Alexandros Frantzis * adapters: Log quirks (82d03bd) * adapters: Add autobrightness quirk for Nexus 4 (e9fb49a) 2016-08-22 Alexandros Frantzis * Prepare for 2016.08.2 release (9e4a848) 2016-08-20 Alexandros Frantzis * adapters: Fix autobrightness behavior (LP: #1613871) (051515d) 2016-08-17 Alexandros Frantzis * debian: Update changelog for new fix (04120eb) * repowerd: Change reduced (AKA short) timeout to 10s (f7cb388) * Fix "The call screen still turns off after rejecting the call on the remote end without answering." (LP: #1613506) (49b0ee4) 2016-08-16 Alexandros Frantzis * Prepare for 2016.08.1 release (25ffea5) 2016-08-12 Alexandros Frantzis * Don't turn off the screen immediately after a keep on request is cancelled and timeouts have expired (6b1f405) 2016-08-11 Alexandros Frantzis * Prepare files for 2016.08 release (5224039) 2016-08-09 Alexandros Frantzis * Fix suspending during video playback when USB gets unplugged (LP #1602933) (011b5f1) 2016-08-08 Alexandros Frantzis * debian: Silently fail if lxc-android-config.service is missing (33fd6fc) 2016-08-05 Alexandros Frantzis * Fix build with g++-6 (b046a41) 2016-07-25 Alexandros Frantzis * debian: Update changelog (115d87c) 2016-07-13 Michał Sawicz * Wants, not Requires lxc-android-config (LP: #1602597) (452cc65) 2016-07-06 Alexandros Frantzis * debian: More packaging improvements (b19a738) * debian: Update Vcs-Git field (279f26e) 2016-07-05 Alexandros Frantzis * debian: Update changelog with needs-packaging LP bug (dd5494c) * debian: Format is 3.0 (native) (3b9966d) 2016-06-13 Alexandros Frantzis * adapters: Ignore stray proximity events when the proximity sensor is disabled (4a6508d) 2016-06-10 Alexandros Frantzis * tests: Change how we split tests into executables (32810a3) * Abstract time-related operations and use fake time in tests (b0a123d) * Abstract filesystem access and remove FUSE test dependency (8db2296) * tools: Use DefaultDaemonConfig to create components in tools (0cf8a8e) 2016-06-09 Alexandros Frantzis * debian: Update changelog (72ec03e) * repowerd: Log repowerd version (7829fb2) 2016-06-08 Alexandros Frantzis * Fix clang build (a3e716a) 2016-06-07 Alexandros Frantzis * adapters: Choose sysfs backlight based on type (d5a7dd6) * adapters: Log used sysfs backlight path (32dddcb) * repowerd: The proximity state of NullProximitySensor is always far (ebe9905) * adapters: Remove printf messages from mocksuspend backend (7290b72) * repowerd: Log fallbacks to null components implementations (5067905) * repowerd: Allow running without brightness control (7ddb93d) * tests: Update filters for tests that need FUSE or are time-sensitive (e0ae829) * adapters: Fix SysfsBacklight::get_brightness() to return the last set brightness value, unless brightness was changed externally (e7ca8e6) 2016-06-06 Alexandros Frantzis * adapters: Refactor path handling (db1f78a) * tests: Support symlinks in VirtualFilesystem (9c6b490) 2016-06-03 Alexandros Frantzis * tools: Informational message improvements (ebc3837) * Support disabling time-sensitive integration tests (90c2ba5) 2016-06-01 Alexandros Frantzis * tests: Include forgotten header (a7565bc) * Round brightness calculations for better accuracy (29461c8) * Misc fixes (c5daeb6) * debian: Explicitly state arch-unqualified package name in powerd maintscript to allow proper conf file removal (ad44678) 2016-05-31 Alexandros Frantzis * debian: Build depend on libubuntu-platform-hardware-api-dev instead of -headers (eda9bfd) * adapters: Log android properties (d5c6805) * adapters: Properly read device-specific config file (5c23f44) * adapters: Add logging to AndroidDeviceConfig (10f7c30) 2016-05-30 Alexandros Frantzis * debian: Use an init system neutral postrotation command for logrotate (aa9275e) * adapters: Transition directly to new brightness value if current value is unknown (06ae913) * Use double instead of float where possible (4cf5cb9) * debian: Make repowerd packages depend on specific versions of other repowerd packages (50039b5) * tools: Add and ship (re)powerd-cli utility (700f4ae) * tests: Keep trying to unmount fuse filesystems on tear down (7661853) * core: Change disable_inactivity_timeouts to brighten/turn on the display (d6d0c08) * debian: Remove powerd conf files (a178495) * debian: Update package version (a575824) 2016-05-27 Alexandros Frantzis * adapters: Implement and use UPower based power source (1bc6ea7) * adapters: Implement and use system shutdown control (a370dbf) * core: Add handling of critical power source state (8f0d300) 2016-05-26 Alexandros Frantzis * core: Add PowerSource and core logic (235a857) * repowerd: Properly shutdown on SIGINT and SIGTERM signals (8ade3f7) * core: Change internal daemon loop terminology (Event->Action) (b32c3ff) * repowerd: Read first from powerd device config directory for compatibility reasons (3dcbe44) 2016-05-25 Alexandros Frantzis * debian: Add logrotate configuration (1b6e9ef) * debian: Add rsyslog configuration (1fc7669) * data,debian: Install dbus conf files (12c4472) * debian: Add repowerd init system startup files (643e567) * debian: Update packaging (4cfdcde) * build: Install repowerd and tools to sbin (e7f72ad) * data: Add device config files (2b486d6) 2016-05-24 Alexandros Frantzis * tests: Fix build errors with stricter debian flags (fd252bc) * adapters: Log brightness transitions (43e9cb5) * adapters: Add a quirk for the type (near/far) of the synthetic initial proximity event (86153b7) 2016-05-23 Alexandros Frantzis * adapters: Implement Ubuntu platform API based performance booster (d0e3c02) * core,tests: Add performance booster and logic (8dd2c3e) * adapters: Print timestamp of each log entry in ConsoleLog (d2d61dc) 2016-05-20 Alexandros Frantzis * adapters: Add libsuspend based suspend control (08eea7e) * core,adapters: Add SuspendControl and logic (a43fc34) 2016-05-23 Alexandros Frantzis * adapters: Make all public BacklightBrightnessControl methods synchronous (a2384d9) 2016-05-19 Alexandros Frantzis * adapters: Add logging to OfonoVoiceCallService (36da37f) * repowerd: Use the ofono based modem power control by default (be2de2d) * adapters: Implement ofono based modem power control (64e78c5) 2016-05-18 Alexandros Frantzis * tests: Use a variable of the correct type uint64_t when creating a GVariant containing a time value (a6ecd8b) * core: Add ModemPowerControl and logic (5ca84af) * core: Don't store shared_ptr to unused object (6604dec) 2016-05-13 Alexandros Frantzis * core,adapters: Add logging (30125fc) 2016-05-18 Alexandros Frantzis * core: Initialize forgotten DefaultStateMachine instance variable (b95675e) 2016-05-17 Alexandros Frantzis * tests: Add some tests for AndroidAutobrightnessAlgorithm (3c1e788) * adapters: Improve robustness against crashes of clients emitting notifications (49e340a) * adapters: Don't emit brightness notification if brightness hasn't changed (13284c5) 2016-05-16 Alexandros Frantzis * tests: Add tests for AndroidBacklight (712ec75) 2016-05-12 Alexandros Frantzis * adapters: Introduce and use an Android libhardware based backlight (a332076) * repowerd: Fall back to a null light sensor if a real one is not available (123a93c) * repowerd: Use separate backlight and light sensor creation methods in DefaultDaemonConfig (392fef0) * adapters: Fix off-by-one error in MonotoneSpline (0b27334) * adapters: Implement brightness change notification over DBus (eebc906) 2016-05-10 Alexandros Frantzis * adapters: Implement autobrightness (736c165) 2016-05-12 Alexandros Frantzis * adapters: Use g_variant_iter_next() to avoid memory errors (4ec2fa1) 2016-05-11 Alexandros Frantzis * debian,build: Build depend on android-headers (73a601c) * adapters: Don't allow MonotoneSplines with fewer than two points (a1a2869) 2016-05-10 Alexandros Frantzis * adapters: Ensure registering an object or signal handlers are synchronous (711c6b2) 2016-05-09 Alexandros Frantzis * core: Remove ProximitySensor::start_processing() (a6e76c1) * adapters,tool: Implement UbuntuLightSensor and related light tool (eaee111) * tests: Extract TemporaryEnvironmentValue and TemporaryFile classes (8079eb8) * adapters: Implement monotone spline class (78f856e) * Use static libraries with transitive usage requirements instead of object libraries (fc78512) 2016-05-05 Alexandros Frantzis * adapters: Refactor BacklightBrightnessControl (previously SysfsBrightnessControl) to not depend on a specific backlight control technology (4dd45d2) 2016-05-04 Alexandros Frantzis * adapters: Translate DBus setInactivityTimeouts request infinite timeout value to repowerd infinite timeout value (cee3aba) * core: Ignore invalid values for inactivity timeouts (0a62fb1) * core: Properly handle requests to disable inactivity timeouts (4054d80) 2016-04-27 Alexandros Frantzis * adapters: Add ofono based voice call service (08c78da) * adapters: Powerd DBus API sys state should only affect system suspend, not display power (05d722e) * tests: Fix race in test expectations (2d4bec1) 2016-04-26 Alexandros Frantzis * adapters: Introduce mechanism to unregister dbus object and signal handlers (226f492) 2016-04-25 Alexandros Frantzis * adapters: Transition smoothly between brightness values (69d24f5) 2016-04-22 Alexandros Frantzis * tools: Add wakeup tool (3585617) * adapters: Add /dev/alarm based wakeup service (12ecb2e) 2016-04-25 Alexandros Frantzis * adapters: Support Powerd DBus API wakeup requests (d6b12db) 2016-04-21 Alexandros Frantzis * adapters: Calculate default brightness values based on device config (1a25677) * adapters: Merge PowerdService into UnityScreenService (c1d6b68) * core,adapters: Ensure we start processing requests after all handlers have been registered (08e1427) 2016-04-20 Alexandros Frantzis * adapters: Add forgotten "#pragma once" (597c96f) * core: Small DefaultStateMachine refactoring (ab16485) * adapters: Scale brightness values requested by users using the device config brightness values (61baad1) * adapters: Implement part of the com.canonical.powerd dbus API (cc9f99d) 2016-04-15 Alexandros Frantzis * core: Improve notification handling (c9a28fa) * tests: Fix initialization of fuse_ops struct to support gcc-4.9 (91943d8) * repowerd: Turn on display at startup (5b96d0b) 2016-04-14 Alexandros Frantzis * tests: Check for existence of fuse only when building the tests (ba9a071) * debian: Build depend on 'fuse' package (f848e0f) * repowerd: Use production components instead of null implementation where possible (8e4d663) * adapters: First cut at SysfsBrightnessControl (900f44b) 2016-04-13 Alexandros Frantzis * tests: Add virtual filesystem infrastructure (e8a1169) 2016-04-12 Alexandros Frantzis * adapters: Implement an event loop based timer (e986d86) * core: Add Timer::cancel_alarm() (52cbb0b) 2016-04-11 Alexandros Frantzis * adapters: Implement DBus based user activity (f35cb84) * adapters: Implement a DBus based power button event sink (b7b93bd) * adapters: Implement DBus based power button (e8fc886) * adapters: Fix UnityDisplayPowerControl header (66cd5b7) 2016-04-08 Alexandros Frantzis * adapters: Implement DBus based display power control (2e84337) * adapters: Improve UbuntuProximitySensor concurrency correctness (e1cddb2) * adapters: Introduce device quirks support (77043ff) 2016-04-07 Alexandros Frantzis * tools: Add proximity tool (d92851a) * Update debian/control build-deps (09d59dd) * adapters: Implement proximity sensor based on ubuntu-application-api (993536b) 2016-04-05 Alexandros Frantzis * adapters: Implement display power event notification in UnityScreenService (bd33a07) 2016-04-04 Alexandros Frantzis * core: Implement display power event notification logic (19c8157) 2016-04-01 Alexandros Frantzis * adapters: Properly register and unregister handlers in UnityScreenService (ff7092e) * adapters: Add notification support to UnityScreenService (044b05f) 2016-03-31 Alexandros Frantzis * tests,adapters: First cut at DBus infrastructure and UnityScreenService (74ec4ff) 2016-03-29 Alexandros Frantzis * core: Move core code into core/ directory (26f4ad6) * tests: Fix race in acceptance tests (57eba3e) * daemon,tests: Implement 'set_inactivity_timeout' client request (81c11e8) 2016-03-28 Alexandros Frantzis * daemon,tests: Implement 'enable/disable_autobrightness' client requests (3b29dcc) * daemon,tests: Implement 'set_normal_brightness_value' client request (0e9e52a) 2016-03-23 Alexandros Frantzis * daemon,tests: Support voice call use cases (c8294a6) 2016-03-24 Alexandros Frantzis * tests: Deduplicate timeout variables (793f95c) 2016-03-23 Alexandros Frantzis * daemon,tests: Support more notification use cases (c390c3e) 2016-03-21 Alexandros Frantzis * daemon,tests: Support inactivity timeout dispaly dimming (7bb1bc0) 2016-03-18 Alexandros Frantzis * daemon,tests: Support notification use cases (2a0eb40) 2016-03-17 Alexandros Frantzis * daemon,tests: Support "enable/disable_inactivity_timeout" client request and remove "turn_on_display" request (dbf4738) * Refactor handler registration and unregistration (8489673) 2016-03-11 Alexandros Frantzis * daemon,tests: Support "turn_on_display" client request (29cb01c) 2016-03-10 Alexandros Frantzis * daemon,tests: Fix power button long press behavior (8e60c78) * daemon,tests: Support proximity use cases (d300ca0) 2016-03-09 Alexandros Frantzis * tests: Improve test names (964f422) * daemon,tests: Implement user activity use cases (a742b9f) * Introduce DaemonConfig methods for timeouts (a9d3a28) * tests: Deduplicate common acceptance test code (e1755f0) * daemon,tests: Added basic user inactivity display blanking logic (108011d) 2016-03-08 Alexandros Frantzis * Be consistent about using "power button" vs "power key" (648ddb4) * tests: Add unit tests for repowerd::Daemon (e6c730c) * tests: Add power button long press acceptance tests (1f4c4b6) 2016-03-03 Alexandros Frantzis * More power button tests and logic (422ad61) * Remove redundant curly braces (09f2e18) 2016-03-02 Alexandros Frantzis * Add a simple event loop and StateMachine abstraction (dd45f05) * Walking skeleton (1ad0bdb) repowerd-2023.07/cmake/000077500000000000000000000000001446034100200145705ustar00rootroot00000000000000repowerd-2023.07/cmake/FindAndroidHeaders.cmake000066400000000000000000000003041446034100200212440ustar00rootroot00000000000000include(CheckIncludeFiles) check_include_files(android/linux/android_alarm.h HAVE_ANDROID_HEADERS) if(NOT HAVE_ANDROID_HEADERS) message(FATAL_ERROR "Could not find android headers") endif() repowerd-2023.07/data/000077500000000000000000000000001446034100200144215ustar00rootroot00000000000000repowerd-2023.07/data/CMakeLists.txt000066400000000000000000000025661446034100200171720ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis FILE(GLOB device_config_files "${CMAKE_CURRENT_SOURCE_DIR}/device-configs/*.xml") FILE(GLOB dbus_config_files "${CMAKE_CURRENT_SOURCE_DIR}/dbus-configs/*.conf") FILE(GLOB systemd_file "${CMAKE_CURRENT_SOURCE_DIR}/repowerd.service") install( FILES ${device_config_files} DESTINATION ${REPOWERD_DEVICE_CONFIG_DIR} ) install( FILES ${dbus_config_files} DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d ) pkg_check_modules(SYSTEMD systemd) if (${SYSTEMD_FOUND}) pkg_get_variable(SYSTEMD_SYSTEM_DIR systemd systemdsystemunitdir) message (STATUS "${SYSTEMD_SYSTEM_DIR} is the systemd system unit file install dir") install (FILES "${systemd_file}" DESTINATION "${SYSTEMD_SYSTEM_DIR}") endif() repowerd-2023.07/data/dbus-configs/000077500000000000000000000000001446034100200170045ustar00rootroot00000000000000repowerd-2023.07/data/dbus-configs/com.canonical.Unity.Screen.conf000066400000000000000000000011461446034100200247060ustar00rootroot00000000000000 repowerd-2023.07/data/dbus-configs/com.lomiri.Repowerd.Settings.conf000066400000000000000000000011061446034100200253060ustar00rootroot00000000000000 repowerd-2023.07/data/dbus-configs/com.lomiri.Repowerd.conf000066400000000000000000000045771446034100200235260ustar00rootroot00000000000000 repowerd-2023.07/data/device-configs/000077500000000000000000000000001446034100200173065ustar00rootroot00000000000000repowerd-2023.07/data/device-configs/config-default.xml000066400000000000000000000076621446034100200227320ustar00rootroot00000000000000 false 4 680 10 255 102 10 repowerd-2023.07/data/device-configs/config-flo.xml000066400000000000000000000066361446034100200220660ustar00rootroot00000000000000 true 5 15 50 100 200 400 1000 2000 3000 5000 10000 30000 11 18 27 38 48 55 64 74 120 164 225 255 255 5 87 5 600 repowerd-2023.07/data/device-configs/config-grouper.xml000066400000000000000000000056651446034100200227720ustar00rootroot00000000000000 true 5 15 50 100 200 400 1000 2000 3000 5000 10000 30000 5 20 30 40 50 60 70 80 130 180 255 255 255 5 repowerd-2023.07/data/device-configs/config-hammerhead.xml000066400000000000000000000063051446034100200233720ustar00rootroot00000000000000 true 1 4 40 350 600 1000 1600 3000 10000 13 26 73 88 130 167 204 240 254 255 1 82 1 600 repowerd-2023.07/data/device-configs/config-maguro.xml000066400000000000000000000054261446034100200225740ustar00rootroot00000000000000 true 6 9 14 20 30 46 68 103 154 231 346 519 778 1168 1752 2627 3941 5912 8867 19 23 26 30 34 39 45 51 59 67 77 88 101 116 133 152 174 199 228 250 10 repowerd-2023.07/data/device-configs/config-mako.xml000066400000000000000000000065261446034100200222330ustar00rootroot00000000000000 true 10 50 100 200 400 500 800 1000 1600 3000 10000 14 28 37 51 71 80 96 108 144 181 254 255 1 87 1 600 repowerd-2023.07/data/device-configs/config-manta.xml000066400000000000000000000066241446034100200224030ustar00rootroot00000000000000 true 10 30 90 15000 225000 10 13 65 85 220 255 2 repowerd-2023.07/data/repowerd.service000066400000000000000000000005011446034100200176260ustar00rootroot00000000000000[Unit] Description=monitor and control system power state Wants=lxc-android-config.service dbus.socket socketfwd.service After=lxc-android-config.service dbus.socket [Service] Type=dbus BusName=com.lomiri.Repowerd ExecStart=/usr/sbin/repowerd EnvironmentFile=-/etc/default/repowerd [Install] WantedBy=multi-user.target repowerd-2023.07/debian/000077500000000000000000000000001446034100200147325ustar00rootroot00000000000000repowerd-2023.07/debian/20-repowerd.conf000066400000000000000000000001201446034100200176400ustar00rootroot00000000000000:programname,isequal,"repowerd" /var/log/repowerd.log;RSYSLOG_FileFormat & stop repowerd-2023.07/debian/Jenkinsfile000066400000000000000000000006511446034100200171200ustar00rootroot00000000000000@Library('ubports-build-tools') _ buildAndProvideDebianPackage() // Or if the package consists entirely of arch-independent packages: // (optional optimization, will confuse BlueOcean's live view at build stage) // buildAndProvideDebianPackage(/* isArchIndependent */ true) // Optionally, to skip building on some architectures (amd64 is always built): // buildAndProvideDebianPackage(false, /* ignoredArchs */ ['arm64']) repowerd-2023.07/debian/changelog000066400000000000000000000113251446034100200166060ustar00rootroot00000000000000repowerd (2023.07) unstable; urgency=medium * Upstream-provided Debian package for repowerd. See upstream ChangeLog for recent changes. -- UBports developers Thu, 27 Jul 2023 03:01:54 +0200 repowerd (2022.01) unstable; urgency=medium * Upstream-provided Debian package for repowerd. See upstream ChangeLog for recent changes. -- UBports developers Wed, 02 Feb 2022 12:51:38 +0100 repowerd (2018.04+ubports) xenial; urgency=medium * Import to UBports * Always set brightness before first autobrightness setting -- Marius Gripsgard Mon, 15 Jan 2018 15:45:57 +0100 repowerd (2017.03+17.04.20170403-0ubuntu1) zesty; urgency=medium * 2017.03 release - Fix "Closing the lid does not suspend the device" (LP: #1668596) - Fix "messages are logged on every input event" (LP: #1674736) - Fix brightness issues when turning on the screen on Fairphone 2 - Add apport hook -- Alexandros Frantzis Mon, 03 Apr 2017 14:19:32 +0000 repowerd (2017.02+17.04.20170221-0ubuntu1) zesty; urgency=medium * 2017.02 release - Improve lid handling - Add timerfd based wakeup service for desktop - Support new power settings, exposed through com.canonical.repowerd - Improve handling of critically low power scenarios - Generate random cookies for wakeup requests * 2017.02 release -- Alexandros Frantzis Tue, 21 Feb 2017 11:41:12 +0000 repowerd (2016.12+17.04.20161212.1-0ubuntu1) zesty; urgency=medium * New 2016.12 release - Support suspending with logind - Implement basic lid handling - Don't change the display power mode when pressing the power button on non-phablet devices. - Various snap-related improvements - Fix "[mako] Alarm doesn't ring when screen locked" (LP: #1588526) - Fix "[mako] Awful life battery since OTA 13" (LP: #1630382) -- Alexandros Frantzis Mon, 12 Dec 2016 19:02:03 +0000 repowerd (2016.11+17.04.20161124-0ubuntu1) zesty; urgency=medium * New 2016.11 release - Support multiple user sessions - Don't interfere with the power state of non-mir sessions - Start repowerd at boot on desktop systems -- Alexandros Frantzis Thu, 24 Nov 2016 12:55:52 +0000 repowerd (2016.10+16.10.20161007-0ubuntu1) yakkety; urgency=medium * New 2016.10 release - Fix typo in brightness config value (LP: #1618391) - Update repowerd-cli help text - Handle SIGTERM gracefully in repowerd-cli - Wait for the repowerd DBus API to be accessible before marking the upstart job as started (LP: #1623853) * 2016.10 release -- Alexandros Frantzis Fri, 07 Oct 2016 11:50:44 +0000 repowerd (2016.08.3+16.10.20160830.1-0ubuntu1) yakkety; urgency=medium * New 2016.08.3 release - Fix "Low battery notification turns screen on and never turns it off again." (LP: #1618417) - Fix "lock display when idle timeout not honoured" (LP: #1615001) - Fix "Missing powerd-cli active" (LP: #1618072) -- Alexandros Frantzis Tue, 30 Aug 2016 16:36:58 +0000 repowerd (2016.08.2+16.10.20160823.1-0ubuntu1) yakkety; urgency=medium * New 2016.08.2 release - Fix "Regression: In dark conditions autobrightness does not adapt" (LP: #1613871) -- Alexandros Frantzis Tue, 23 Aug 2016 14:22:58 +0000 repowerd (2016.08.1+16.10.20160817.1-0ubuntu1) yakkety; urgency=medium * New 2016.08.1 release - Fix "Display turns off right after playing back a long video" (LP: #1602739) - Fix "call screen still turns off after rejecting the call on the remote end without answering." (LP: #1613506) -- Alexandros Frantzis Wed, 17 Aug 2016 17:48:35 +0000 repowerd (2016.08+16.10.20160811-0ubuntu1) yakkety; urgency=medium * New 2016.08 release - Fix "suspends during video playback when USB gets unplugged" (LP: #1602933) -- Alexandros Frantzis Thu, 11 Aug 2016 14:17:03 +0000 repowerd (2016.06+16.10.20160808-0ubuntu1) yakkety; urgency=medium * debian/repowerd.service: - Make service dependency on lxc-android-config.service optional ('Wants' instead of 'Requires') - Silently fail if lxc-android-config.service is missing -- Alexandros Frantzis Mon, 08 Aug 2016 08:59:28 +0000 repowerd (2016.06+16.10.20160706.1-0ubuntu1) yakkety; urgency=medium * Initial release (LP: #1599271) -- Alexandros Frantzis Wed, 06 Jul 2016 14:24:10 +0000 repowerd-2023.07/debian/compat000066400000000000000000000000021446034100200161300ustar00rootroot000000000000009 repowerd-2023.07/debian/control000066400000000000000000000041731446034100200163420ustar00rootroot00000000000000Source: repowerd Priority: optional Section: admin Maintainer: Ubuntu Developers Build-Depends: debhelper (>= 9), dh-apport, dh-systemd, android-headers, cmake, cmake-extras, dbus, googletest | google-mock, libdeviceinfo-dev, libgbinder-dev, libglib2.0-dev, libgtest-dev, pkg-config, systemd [linux-any], Standards-Version: 3.9.7 Homepage: https://launchpad.net/repowerd Vcs-Git: https://git.launchpad.net/repowerd Package: repowerd Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, repowerd-data (= ${source:Version}) Replaces: powerd (<< 2016.05~) Breaks: powerd (<< 2016.05~) Provides: powerd Description: Power daemon to monitor and control system power state This daemon monitors and controls system power states for Ubuntu phone and tablet. . This package contains repowerd daemon itself. Package: repowerd-data Architecture: all Depends: ${misc:Depends} Conflicts: powerd (<< 2016.05~) Description: Power daemon to monitor and control system power state This daemon monitors and controls system power states for Ubuntu phone and tablet. . This package contains data files needed by repowerd. Package: repowerd-tools Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, repowerd-data (= ${source:Version}) Description: Power daemon to monitor and control system power state This daemon monitors and controls system power states for Ubuntu phone and tablet. It provides a dbus interface for system services to request a power state, essentially allowing services to block suspend. . This package contains tools that use the repowerd infrastructure to interact with various hardware components. These tools are mainly useful for manual integration testing. Package: powerd Architecture: all Depends: ${misc:Depends}, repowerd (>= ${source:Version}) Section: oldlibs Description: Transitional dummy package This is a transitional dummy package. repowerd-2023.07/debian/copyright000066400000000000000000000020751446034100200166710ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Power daemon to monitor power button events Upstream-Contact: Alexandros Frantzis Source: https://launchpad.net/repowerd Files: * Copyright: Copyright (C) 2016, Canonical Ltd License: GPL-3 License: GPL-3 This program is free software: you can redistribute it and/or modify it under the terms of the the GNU General Public License version 3, as published by the Free Software Foundation. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable version of the GNU Lesser General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-3' repowerd-2023.07/debian/powerd.maintscript000066400000000000000000000001571446034100200205140ustar00rootroot00000000000000rm_conffile /etc/dbus-1/system.d/powerd.conf 2016.06~ powerd rm_conffile /etc/init/powerd.conf 2016.06~ powerd repowerd-2023.07/debian/repowerd-data.install000066400000000000000000000000231446034100200210530ustar00rootroot00000000000000usr/share/repowerd repowerd-2023.07/debian/repowerd-data.links000066400000000000000000000001501446034100200205260ustar00rootroot00000000000000usr/share/repowerd/device-configs/config-default.xml usr/share/powerd/device_configs/config-default.xml repowerd-2023.07/debian/repowerd-tools.install000066400000000000000000000000311446034100200213010ustar00rootroot00000000000000usr/sbin/repowerd-*-tool repowerd-2023.07/debian/repowerd.apport000066400000000000000000000011541446034100200200110ustar00rootroot00000000000000'''apport package hook for repowerd Copyright (c) 2017 Canonical Ltd. Author: Alexandros Frantzis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. See http://www.gnu.org/copyleft/gpl.html for the full text of the license. ''' from apport.hookutils import * def add_info(report, ui=None): attach_file_if_exists(report, '/var/log/repowerd.log', key='repowerd.log') attach_file_if_exists(report, '/var/log/repowerd.log.1', key='repowerd.log.1') repowerd-2023.07/debian/repowerd.default000066400000000000000000000005031446034100200201250ustar00rootroot00000000000000# to be overlaid by ports # # REPOWERD_DEVICE_CONFIG_DIR=/usr/share/repowerd/device-configs # REPOWERD_LOG=(syslog|console|null) # REPOWERD_LOG_LEVEL=(debug|info|warning) # REPOWERD_LOG_AUTOBRIGHTNESS=true # REPOWERD_QUIRK_NORMAL_BEFORE_DISPLAY_ON_AUTOBRIGHTNESS=(always|never) # SENSORFW_SOCKET_PATH=/var/run/sensord.sock repowerd-2023.07/debian/repowerd.install000066400000000000000000000002161446034100200201500ustar00rootroot00000000000000usr/sbin/repowerd usr/sbin/repowerd-cli etc/dbus-1/system.d/*.conf lib/systemd/system/repowerd.service debian/20-repowerd.conf etc/rsyslog.d/ repowerd-2023.07/debian/repowerd.links000066400000000000000000000000521446034100200176200ustar00rootroot00000000000000usr/sbin/repowerd-cli usr/sbin/powerd-cli repowerd-2023.07/debian/repowerd.logrotate000066400000000000000000000003111446034100200204760ustar00rootroot00000000000000/var/log/repowerd.log { daily missingok rotate 4 compress notifempty delaycompress maxsize 10M postrotate kill -HUP $(cat /var/run/rsyslogd.pid) endscript } repowerd-2023.07/debian/rules000077500000000000000000000005121446034100200160100ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ --parallel --fail-missing --with apport,systemd override_dh_auto_configure: dh_auto_configure -- \ -DREPOWERD_ENABLE_HYBRIS=OFF \ -DREPOWERD_ENABLE_BINDER=ON \ -DREPOWERD_DISABLE_TIME_SENSITIVE_TESTS=ON repowerd-2023.07/debian/source/000077500000000000000000000000001446034100200162325ustar00rootroot00000000000000repowerd-2023.07/debian/source/format000066400000000000000000000000151446034100200174410ustar00rootroot000000000000003.0 (native) repowerd-2023.07/doc/000077500000000000000000000000001446034100200142555ustar00rootroot00000000000000repowerd-2023.07/doc/repowerd-settings-api.txt000066400000000000000000000032061446034100200212530ustar00rootroot00000000000000Service : com.lomiri.Repowerd.Settings Interface : com.lomiri.Repowerd.Settings ObjectPath: /com/lomiri/Repowerd/Settings Methods ------- void SetInactivityBehavior(string power_action, string power_source, int timeout_sec) : "display-off", "suspend" : "battery", "line-power" : positive timeout in seconds, non-positive to disable Sets the inactivity behavior to while on after seconds. Examples: While on battery turn off display after 30 seconds of inactivity: SetInactivityBehavior("display-off", "battery", 30) While plugged in never turn off display due to inactivity: SetInactivityBehavior("display-off", "line-power", -1) While on battery suspend after 10 minutes of inactivity: SetInactivityBehavior("suspend", "battery", 600) void SetLidBehavior(string power_action, string power_source) : "none", "suspend" : "battery", "line-power" Sets the lid behavior to while on . Examples: While on battery suspend when closing the lid: SetLidBehavior("suspend", "battery") While plugged in do nothing when closing the lid: SetLidBehavior("none", "line-power") void SetCriticalPowerBehavior(string power_action) : "suspend", "power-off" Sets the critical power behavior to . Examples: Power off the device when power is critically low: SetCriticalPowerBehavior("power-off") repowerd-2023.07/src/000077500000000000000000000000001446034100200142775ustar00rootroot00000000000000repowerd-2023.07/src/CMakeLists.txt000066400000000000000000000030001446034100200170300ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis add_definitions(-DPOWERD_DEVICE_CONFIG_DIR=\"${POWERD_DEVICE_CONFIG_DIR}\") add_definitions(-DREPOWERD_DEVICE_CONFIG_DIR=\"${REPOWERD_DEVICE_CONFIG_DIR}\") include_directories( ${CMAKE_SOURCE_DIR} ) if (REPOWERD_ENABLE_HYBRIS) add_definitions(-DREPOWERD_ENABLE_HYBRIS) endif() if (REPOWERD_ENABLE_BINDER) add_definitions(-DREPOWERD_ENABLE_BINDER) endif() add_subdirectory(core) add_subdirectory(adapters) add_subdirectory(tools) add_library( repowerd-default-daemon-config STATIC default_daemon_config.cpp ) target_link_libraries( repowerd-default-daemon-config repowerd-core repowerd-adapters ) add_executable( repowerd main.cpp ) target_link_libraries( repowerd repowerd-core repowerd-adapters repowerd-default-daemon-config ) install( TARGETS repowerd RUNTIME DESTINATION sbin ) repowerd-2023.07/src/adapters/000077500000000000000000000000001446034100200161025ustar00rootroot00000000000000repowerd-2023.07/src/adapters/CMakeLists.txt000066400000000000000000000057041446034100200206500ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis add_subdirectory(libsuspend) if (REPOWERD_ENABLE_HYBRIS) set(REPOWERD_ADAPTER_HYBRIS_SRCS android_backlight.cpp dev_alarm_wakeup_service.cpp ubuntu_light_sensor.cpp ubuntu_performance_booster.cpp ubuntu_proximity_sensor.cpp ) endif() if (REPOWERD_ENABLE_BINDER) set(REPOWERD_ADAPTER_BINDER_SRCS binder_performance_booster.cpp ) endif() set( REPOWERD_ADAPTER_SRCS android_autobrightness_algorithm.cpp android_device_config.cpp android_device_quirks.cpp backlight_brightness_control.cpp brightness_params.cpp console_log.cpp dbus_connection_handle.cpp dbus_event_loop.cpp dbus_message_handle.cpp default_state_machine_options.cpp fs_double_tap_to_wake.cpp event_loop.cpp event_loop_timer.cpp fd.cpp libsuspend_system_power_control.cpp logind_session_tracker.cpp logind_system_power_control.cpp lsc_display.cpp lsc_power_button.cpp lsc_user_activity.cpp monotone_spline.cpp null_log.cpp ofono_voice_call_service.cpp path.cpp real_chrono.cpp real_device_info.cpp real_filesystem.cpp real_temporary_suspend_inhibition.cpp repowerd_settings_service.cpp syslog_log.cpp sysfs_backlight.cpp timerfd_wakeup_service.cpp unity_screen_service.cpp upower_power_source_and_lid.cpp sensorfw/sensorfw_common.cpp sensorfw/sensorfw_light_sensor.cpp sensorfw/sensorfw_proximity_sensor.cpp sensorfw/socketreader.cpp ${REPOWERD_ADAPTER_HYBRIS_SRCS} ${REPOWERD_ADAPTER_BINDER_SRCS} ) add_library( repowerd-adapters STATIC ${REPOWERD_ADAPTER_SRCS} ) target_link_libraries( repowerd-adapters suspend ${DEVICEINFO_LDFLAGS} ${GIO_LDFLAGS} ${GIO_LIBRARIES} ${GIO_UNIX_LDFLAGS} ${GIO_UNIX_LIBRARIES} ${LIBHARDWARE_LDFLAGS} ${LIBHARDWARE_LIBRARIES} ${UA_LDFLAGS} ${UA_LIBRARIES} ${UBUNTU_PLATFORM_HARDWARE_API_LDFLAGS} ${UBUNTU_PLATFORM_HARDWARE_API_LIBRARIES} ${GBINDER_LDFLAGS} ${GBINDER_LIBRARIES} ) target_include_directories( repowerd-adapters PUBLIC ${DEVICEINFO_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIO_UNIX_INCLUDE_DIRS} ${LIBHARDWARE_INCLUDE_DIRS} ${UA_INCLUDE_DIRS} ${UBUNTU_PLATFORM_HARDWARE_API_INCLUDE_DIRS} ${GBINDER_INCLUDE_DIRS} ) repowerd-2023.07/src/adapters/android_autobrightness_algorithm.cpp000066400000000000000000000220311446034100200254130ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "android_autobrightness_algorithm.h" #include "brightness_params.h" #include "device_config.h" #include "event_loop.h" #include "event_loop_handler_registration.h" #include "src/core/log.h" #include "monotone_spline.h" #include #include #include #include #include namespace { char const* const log_tag = "AndroidAutobrightnessAlgorithm"; auto const null_handler = [](auto){}; auto constexpr smoothing_factor_slow = 2000.0; auto constexpr smoothing_factor_fast = 200.0; auto constexpr hysteresis_factor = 0.1; auto constexpr debounce_delay = std::chrono::seconds{4}; std::vector parse_int_array(std::string const& str) { std::vector elems; std::stringstream ss{str}; std::string item; while (std::getline(ss, item, ',')) elems.push_back(std::stoi(item)); return elems; } std::unique_ptr create_brightness_spline(repowerd::DeviceConfig const& device_config, std::shared_ptr const& log) try { auto const ab_light_levels_str = device_config.get("autoBrightnessLevels", ""); std::string ab_brightness_levels_str = device_config.get("autoBrightnessLcdBacklightValues", ""); if (ab_brightness_levels_str == "") // FIXME screenBrightnessBacklight is supposed to be used with screenBrightnessNits // https://cs.android.com/android/platform/superproject/+/android-security-11.0.0_r64:frameworks/base/core/res/res/values/config.xml;l=1363 // https://gitlab.com/ubports/development/core/repowerd/-/issues/36 ab_brightness_levels_str = device_config.get("screenBrightnessBacklight", ""); if (ab_brightness_levels_str == "") throw std::runtime_error{"Autobrightness not supported - Missing values"}; auto ab_light_levels = parse_int_array(ab_light_levels_str); auto const ab_brightness_levels = parse_int_array(ab_brightness_levels_str); if (ab_light_levels.size() < 1 || ab_brightness_levels.size() < 2 || ab_brightness_levels.size() <= ab_light_levels.size() || ab_brightness_levels.size() > 255) { throw std::runtime_error{"Autobrightness not supported - Values in config are not valid"}; } ab_light_levels.insert(ab_light_levels.begin(), 0); std::vector points; auto l_iter = ab_light_levels.begin(); auto b_iter = ab_brightness_levels.begin(); int brightness_levels_steps = 1; if (ab_brightness_levels.size() > ab_light_levels.size() + 1) brightness_levels_steps = ab_brightness_levels.size() / ab_light_levels.size(); for (; l_iter != ab_light_levels.end() && b_iter != ab_brightness_levels.end(); ++l_iter, b_iter+=brightness_levels_steps) { points.push_back({static_cast(*l_iter), static_cast(*b_iter)}); } return std::make_unique(points); } catch (std::exception& e) { log->log(log_tag, "%s", e.what()); return {}; } double get_max_brightness(repowerd::DeviceConfig const& device_config) { auto const brightness_params = repowerd::BrightnessParams::from_device_config(device_config); return brightness_params.max_value; } double exponential_smoothing( double old_average, double new_value, double smoothing_factor) { return old_average + smoothing_factor * (new_value - old_average); } } repowerd::AndroidAutobrightnessAlgorithm::AndroidAutobrightnessAlgorithm( DeviceConfig const& device_config, std::shared_ptr const& log) : brightness_spline{create_brightness_spline(device_config, log)}, max_brightness{get_max_brightness(device_config)}, log{log}, started{false}, debouncing_seqnum{0} { reset(); } repowerd::AndroidAutobrightnessAlgorithm::~AndroidAutobrightnessAlgorithm() = default; bool repowerd::AndroidAutobrightnessAlgorithm::init(EventLoop& event_loop) { if (!brightness_spline) return false; this->event_loop = &event_loop; return true; } void repowerd::AndroidAutobrightnessAlgorithm::new_light_value(double light) { if (!started) return; auto const is_first_light_value = !have_previous_light_values(); log->logDebug(log_tag, "process_new_light_value(%.2f), is_first_light_value=%d", light, is_first_light_value); update_averages(light); if (is_first_light_value) { notify_brightness(brightness_spline->interpolate(fast_average)); applied_light = fast_average; } else { schedule_debounce(); } } void repowerd::AndroidAutobrightnessAlgorithm::start() { if (!started) { reset(); started = true; } } void repowerd::AndroidAutobrightnessAlgorithm::stop() { if (started) { reset(); started = false; } } repowerd::HandlerRegistration repowerd::AndroidAutobrightnessAlgorithm::register_autobrightness_handler( AutobrightnessHandler const& handler) { return EventLoopHandlerRegistration{ *event_loop, [this, &handler]{ this->autobrightness_handler = handler; }, [this]{ this->autobrightness_handler = null_handler; }}; } void repowerd::AndroidAutobrightnessAlgorithm::reset() { last_light = 0.0; last_light_tp = {}; applied_light = 0.0; fast_average = 0.0; slow_average = 0.0; debouncing = false; ++debouncing_seqnum; } bool repowerd::AndroidAutobrightnessAlgorithm::have_previous_light_values() { return last_light_tp != std::chrono::steady_clock::time_point{}; } void repowerd::AndroidAutobrightnessAlgorithm::update_averages(double light) { auto const now = std::chrono::steady_clock::now(); if (!have_previous_light_values()) { fast_average = light; slow_average = light; } else { auto const dt = now - last_light_tp; double const dt_ms = std::chrono::duration_cast(dt).count(); auto const fast_factor = dt_ms / (dt_ms + smoothing_factor_fast); auto const slow_factor = dt_ms / (dt_ms + smoothing_factor_slow); fast_average = exponential_smoothing(fast_average, light, fast_factor); slow_average = exponential_smoothing(slow_average, light, slow_factor); } last_light_tp = now; last_light = light; } void repowerd::AndroidAutobrightnessAlgorithm::schedule_debounce() { if (debouncing) return; debouncing = true; ++debouncing_seqnum; log->logDebug(log_tag, "schedule_debounce(), seqnum=%d", debouncing_seqnum); event_loop->schedule_in( debounce_delay, [this, expected_debouncing_seqnum=debouncing_seqnum] { if (debouncing_seqnum != expected_debouncing_seqnum) { log->logDebug(log_tag, "debounce() ignored, expected_seqnum=%d, actual_seqnum=%d", expected_debouncing_seqnum, debouncing_seqnum); return; } auto constexpr min_hysteresis = 2.0; debouncing = false; update_averages(last_light); auto const hysteresis = std::max(applied_light * hysteresis_factor, min_hysteresis); auto const slow_delta = slow_average - applied_light; auto const fast_delta = fast_average - applied_light; log->logDebug(log_tag, "debounce(), seqnum=%d, applied_light=%.2f, hysteresis=%.2f, " "slow_average=%.2f, fast_average=%.2f, slow_delta=%.2f, " "fast_delta=%.2f", expected_debouncing_seqnum, applied_light, hysteresis, slow_average, fast_average, slow_delta, fast_delta); if ((slow_delta >= hysteresis && fast_delta >= hysteresis) || (-slow_delta >= hysteresis && -fast_delta >= hysteresis)) { log->logDebug(log_tag, "debounce(), apply light %.2f", fast_average); notify_brightness(brightness_spline->interpolate(fast_average)); applied_light = fast_average; } auto const hysteresis_last_light = std::max(last_light * hysteresis_factor, min_hysteresis); if (fabs(fast_average - last_light) >= hysteresis_last_light) schedule_debounce(); }); } void repowerd::AndroidAutobrightnessAlgorithm::notify_brightness(double brightness) { return autobrightness_handler(brightness / max_brightness); } repowerd-2023.07/src/adapters/android_autobrightness_algorithm.h000066400000000000000000000037141446034100200250670ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "autobrightness_algorithm.h" #include #include namespace repowerd { class DeviceConfig; class Log; class MonotoneSpline; class AndroidAutobrightnessAlgorithm : public AutobrightnessAlgorithm { public: AndroidAutobrightnessAlgorithm( DeviceConfig const& device_config, std::shared_ptr const& log); ~AndroidAutobrightnessAlgorithm(); bool init(EventLoop& event_loop) override; void new_light_value(double light) override; void start() override; void stop() override; HandlerRegistration register_autobrightness_handler( AutobrightnessHandler const& handler) override; private: void reset(); bool have_previous_light_values(); void update_averages(double light); void schedule_debounce(); void notify_brightness(double brightness); EventLoop* event_loop; std::unique_ptr const brightness_spline; double const max_brightness; std::shared_ptr const log; AutobrightnessHandler autobrightness_handler; bool started; std::chrono::steady_clock::time_point last_light_tp; double last_light; double applied_light; double fast_average; double slow_average; bool debouncing; int debouncing_seqnum; }; } repowerd-2023.07/src/adapters/android_backlight.cpp000066400000000000000000000040111446034100200222320ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "android_backlight.h" #include #include #include #include repowerd::AndroidBacklight::AndroidBacklight() : brightness{Backlight::unknown_brightness} { hw_module_t const* hwmod; auto error = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, &hwmod); if (error || hwmod == nullptr) throw std::runtime_error("Failed to open Android lights module"); error = hwmod->methods->open(hwmod, LIGHT_ID_BACKLIGHT, reinterpret_cast(&light_dev)); if (error || light_dev == nullptr) throw std::runtime_error("Failed to open Android backlight device"); } repowerd::AndroidBacklight::~AndroidBacklight() { light_dev->common.close(reinterpret_cast(light_dev)); } void repowerd::AndroidBacklight::set_brightness(double value) { int const value_abs = round(value * 255); light_state_t state; memset(&state, 0, sizeof(light_state_t)); state.flashMode = LIGHT_FLASH_NONE; state.brightnessMode = BRIGHTNESS_MODE_USER; state.color = ((0xffU << 24) | (value_abs << 16) | (value_abs << 8) | value_abs); auto const err = light_dev->set_light(light_dev, &state); if (!err) brightness = value; } double repowerd::AndroidBacklight::get_brightness() { return brightness; } repowerd-2023.07/src/adapters/android_backlight.h000066400000000000000000000020201446034100200216750ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "backlight.h" struct light_device_t; namespace repowerd { class AndroidBacklight : public Backlight { public: AndroidBacklight(); ~AndroidBacklight(); void set_brightness(double) override; double get_brightness() override; private: light_device_t* light_dev; double brightness; }; } repowerd-2023.07/src/adapters/android_device_config.cpp000066400000000000000000000141361446034100200230770ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "android_device_config.h" #include "path.h" #include "src/core/log.h" #include #include #include #include #include #include #include "device_info.h" char const* const log_tag = "AndroidDeviceConfig"; repowerd::AndroidDeviceConfig::AndroidDeviceConfig( std::shared_ptr const& log, std::shared_ptr const& filesystem, std::shared_ptr const& device_info, std::vector const& config_dirs) : log{log}, filesystem{filesystem} { for (auto const& dir : config_dirs) log->logDebug(log_tag, "Using config directory: %s", dir.c_str()); parse_first_matching_file_in_dirs(config_dirs, "config-default.xml"); auto const device_name = device_info->name(); if (device_name != "") parse_first_matching_file_in_dirs(config_dirs, "config-" + device_name + ".xml"); log_properties(); } std::string repowerd::AndroidDeviceConfig::get( std::string const& name, std::string const& default_value) const { auto const iter = config.find(name); if (iter != config.end()) return iter->second; else return default_value; } void repowerd::AndroidDeviceConfig::parse_first_matching_file_in_dirs( std::vector const& config_dirs, std::string const& filename) { for (auto const& config_dir : config_dirs) { auto const full_file_path = Path{config_dir}/filename; if (filesystem->is_regular_file(full_file_path)) { parse_file(full_file_path); break; } } } void repowerd::AndroidDeviceConfig::parse_file(std::string const& file) { log->logDebug(log_tag, "parse_file(%s)", file.c_str()); GMarkupParser parser; parser.start_element = static_xml_start_element; parser.end_element = static_xml_end_element; parser.text = static_xml_text; parser.passthrough = nullptr; parser.error = nullptr; auto const ctx = std::unique_ptr{ g_markup_parse_context_new( &parser, static_cast(0), this, nullptr), g_markup_parse_context_free}; auto const ifs_ptr = filesystem->istream(file); auto& ifs = *ifs_ptr; std::array text; while (ifs) { ifs.read(text.data(), text.size()); auto text_len = ifs.gcount(); g_markup_parse_context_parse( ctx.get(), text.data(), text_len, nullptr); } } void repowerd::AndroidDeviceConfig::static_xml_start_element( GMarkupParseContext* /*context*/, char const* element_name, char const** attribute_names, char const** attribute_values, gpointer user_data, GError** /*error*/) { auto const device_config = static_cast(user_data); std::unordered_map attribs; auto current_attrib = attribute_names; auto current_value = attribute_values; while (*current_attrib != nullptr) { attribs.emplace(*current_attrib, *current_value); ++current_attrib; ++current_value; } device_config->xml_start_element(element_name, attribs); } void repowerd::AndroidDeviceConfig::static_xml_end_element( GMarkupParseContext* /*context*/, char const* element_name, void* user_data, GError** /*error*/) { auto const device_config = static_cast(user_data); device_config->xml_end_element(element_name); } void repowerd::AndroidDeviceConfig::static_xml_text( GMarkupParseContext* /*context*/, char const* text, gsize text_len, gpointer user_data, GError** /*error*/) { auto const device_config = static_cast(user_data); if (text && text_len > 0) device_config->xml_text(std::string{text, text_len}); else device_config->xml_text(""); } void repowerd::AndroidDeviceConfig::xml_start_element( std::string const& element_name, std::unordered_map const& attribs) { if (element_name != "integer" && element_name != "integer-array" && element_name != "bool") return; auto iter = attribs.find("name"); if (iter == attribs.end()) return; auto config_name = iter->second; if (config_name.find("config_") == 0) config_name = config_name.substr(strlen("config_")); last_config_name = config_name; config.erase(last_config_name); } void repowerd::AndroidDeviceConfig::xml_end_element( std::string const& element_name) { if (element_name != "integer" && element_name != "integer-array" && element_name != "bool") return; last_config_name = ""; } void repowerd::AndroidDeviceConfig::xml_text(std::string const& text) { auto clean_text = text; clean_text.erase( std::remove_if(clean_text.begin(), clean_text.end(), [](int c) { return isspace(c); }), clean_text.end()); if (last_config_name == "" || clean_text == "") return; auto iter = config.find(last_config_name); if (iter != config.end()) iter->second += "," + clean_text; else config[last_config_name] = clean_text; } void repowerd::AndroidDeviceConfig::log_properties() { for (auto const& property : config) { log->logDebug(log_tag, "Property: %s=%s", property.first.c_str(), property.second.c_str()); } } repowerd-2023.07/src/adapters/android_device_config.h000066400000000000000000000047101446034100200225410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "device_config.h" #include "filesystem.h" #include #include #include #include namespace repowerd { class Log; class DeviceInfo; class AndroidDeviceConfig : public DeviceConfig { public: AndroidDeviceConfig( std::shared_ptr const& log, std::shared_ptr const& filesystem, std::shared_ptr const& device_info, std::vector const& config_dirs); std::string get( std::string const& name, std::string const& default_value) const override; private: static void static_xml_start_element( GMarkupParseContext* context, char const* element_name, char const** attribute_names, char const** attribute_values, gpointer user_data, GError** error); static void static_xml_end_element( GMarkupParseContext* context, char const* element_name, void* user_data, GError** error); static void static_xml_text( GMarkupParseContext* context, char const* text, gsize text_len, gpointer user_data, GError** error); void parse_first_matching_file_in_dirs( std::vector const& dirs, std::string const& filename); void parse_file(std::string const& file); void xml_start_element( std::string const& element_name, std::unordered_map const& attribs); void xml_end_element(std::string const& element_name); void xml_text(std::string const& text); void log_properties(); std::shared_ptr const log; std::shared_ptr const filesystem; std::string last_config_name; std::unordered_map config; }; } repowerd-2023.07/src/adapters/android_device_quirks.cpp000066400000000000000000000107471446034100200231540ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "android_device_quirks.h" #include "src/core/log.h" #include "device_info.h" using namespace std::chrono_literals; namespace { char const* const log_tag = "AndroidDeviceQuirks"; std::chrono::milliseconds synthetic_initial_proximity_event_delay_for(std::string const& device_name) { // Mako can be a bit slow to report proximity when waking from suspend if (device_name == "mako") return 700ms; else return 500ms; } repowerd::AndroidDeviceQuirks::ProximityEventType synthetic_initial_proximity_event_type_for(std::string device_name) { // In general we assume a "near" state if we don't get an initial event. // However, arale and bacon do not emit an initial event when in the "far" state // in particular, so we assume a "far" state for arale. if (device_name == "arale" || device_name == "bacon" || device_name == "A0001" || device_name == "a0001") return repowerd::AndroidDeviceQuirks::ProximityEventType::far; else return repowerd::AndroidDeviceQuirks::ProximityEventType::near; } bool normal_before_display_on_autobrightness_for(std::string const& device_name) { auto const quirk_cstr = getenv("REPOWERD_QUIRK_NORMAL_BEFORE_DISPLAY_ON_AUTOBRIGHTNESS"); std::string const quirk{quirk_cstr ? quirk_cstr : "always"}; // Mako needs us to manually set the brightness before the first // autobrightness setting after turning on the screen. Otherwise, it // doesn't update screen brightness to the proper level until the next // screen content refresh. return (device_name == "mako" || quirk == "always") && quirk != "never"; } std::string proximity_event_type_to_str( repowerd::AndroidDeviceQuirks::ProximityEventType const type) { switch (type) { case repowerd::AndroidDeviceQuirks::ProximityEventType::near: return "near"; case repowerd::AndroidDeviceQuirks::ProximityEventType::far: return "far"; default: return "unknown"; }; return "unknown"; } } repowerd::AndroidDeviceQuirks::AndroidDeviceQuirks( repowerd::Log& log, std::shared_ptr const& device_info) : device_name_{device_info->name()}, synthetic_initial_proximity_event_delay_{ synthetic_initial_proximity_event_delay_for(device_name_)}, synthetic_initial_proximity_event_type_{ synthetic_initial_proximity_event_type_for(device_name_)}, normal_before_display_on_autobrightness_{ normal_before_display_on_autobrightness_for(device_name_)}, ignore_session_deactivation_{!device_info->is_desktop()} { log.logDebug(log_tag, "DeviceName: %s", device_name_.c_str()); log.logDebug(log_tag, "Quirk: synthetic_initial_proximit_event_delay=%d", static_cast(synthetic_initial_proximity_event_delay_.count())); log.logDebug(log_tag, "Quirk: synthetic_initial_proximit_event_type=%s", proximity_event_type_to_str(synthetic_initial_proximity_event_type_).c_str()); log.logDebug(log_tag, "Quirk: normal_before_display_on_autobrightness=%s", normal_before_display_on_autobrightness_ ? "true" : "false"); log.logDebug(log_tag, "Quirk: ignore_session_deactivation=%s", ignore_session_deactivation_ ? "true" : "false"); } std::chrono::milliseconds repowerd::AndroidDeviceQuirks::synthetic_initial_proximity_event_delay() const { return synthetic_initial_proximity_event_delay_; } repowerd::AndroidDeviceQuirks::ProximityEventType repowerd::AndroidDeviceQuirks::synthetic_initial_proximity_event_type() const { return synthetic_initial_proximity_event_type_; } bool repowerd::AndroidDeviceQuirks::normal_before_display_on_autobrightness() const { return normal_before_display_on_autobrightness_; } bool repowerd::AndroidDeviceQuirks::ignore_session_deactivation() const { return ignore_session_deactivation_; } repowerd-2023.07/src/adapters/android_device_quirks.h000066400000000000000000000030321446034100200226060ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "device_quirks.h" #include #include namespace repowerd { class Log; class DeviceInfo; class AndroidDeviceQuirks : public DeviceQuirks { public: AndroidDeviceQuirks(Log& log, std::shared_ptr const& device_info); std::chrono::milliseconds synthetic_initial_proximity_event_delay() const override; ProximityEventType synthetic_initial_proximity_event_type() const override; bool normal_before_display_on_autobrightness() const override; bool ignore_session_deactivation() const override; private: std::string const device_name_; std::chrono::milliseconds const synthetic_initial_proximity_event_delay_; ProximityEventType const synthetic_initial_proximity_event_type_; bool normal_before_display_on_autobrightness_; bool const ignore_session_deactivation_; }; } repowerd-2023.07/src/adapters/autobrightness_algorithm.h000066400000000000000000000027101446034100200233620ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/handler_registration.h" #include namespace repowerd { using AutobrightnessHandler = std::function; class EventLoop; class AutobrightnessAlgorithm { public: virtual ~AutobrightnessAlgorithm() = default; virtual bool init(EventLoop& event_loop) = 0; virtual void new_light_value(double light) = 0; virtual void start() = 0; virtual void stop() = 0; virtual HandlerRegistration register_autobrightness_handler( AutobrightnessHandler const& handler) = 0; protected: AutobrightnessAlgorithm() = default; AutobrightnessAlgorithm(AutobrightnessAlgorithm const&) = delete; AutobrightnessAlgorithm& operator=(AutobrightnessAlgorithm const&) = delete; }; } repowerd-2023.07/src/adapters/backlight.h000066400000000000000000000020751446034100200202070ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { class Backlight { public: virtual ~Backlight() = default; virtual void set_brightness(double) = 0; virtual double get_brightness() = 0; static double constexpr unknown_brightness = -1.0; protected: Backlight() = default; Backlight(Backlight const&) = delete; Backlight& operator=(Backlight const&) = delete; }; } repowerd-2023.07/src/adapters/backlight_brightness_control.cpp000066400000000000000000000264671446034100200245450ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "autobrightness_algorithm.h" #include "backlight_brightness_control.h" #include "backlight.h" #include "brightness_params.h" #include "chrono.h" #include "device_quirks.h" #include "event_loop_handler_registration.h" #include "light_sensor.h" #include "src/core/log.h" #include #include #include #include #include using namespace std::chrono_literals; namespace { char const* const log_tag = "BacklightBrightnessControl"; auto const null_handler = [](double){}; double normal_brightness_percent(repowerd::DeviceConfig const& device_config) { auto brightness_params = repowerd::BrightnessParams::from_device_config(device_config); return static_cast(brightness_params.default_value) / brightness_params.max_value; } double dim_brightness_percent(repowerd::DeviceConfig const& device_config) { auto const brightness_params = repowerd::BrightnessParams::from_device_config(device_config); return static_cast(brightness_params.dim_value) / brightness_params.max_value; } } repowerd::BacklightBrightnessControl::BacklightBrightnessControl( std::shared_ptr const& backlight, std::shared_ptr const& light_sensor, std::shared_ptr const& autobrightness_algorithm, std::shared_ptr const& chrono, std::shared_ptr const& log, DeviceConfig const& device_config, DeviceQuirks const& quirks) : backlight{backlight}, light_sensor{light_sensor}, autobrightness_algorithm{autobrightness_algorithm}, chrono{chrono}, log{log}, normal_before_display_on_autobrightness{ quirks.normal_before_display_on_autobrightness()}, ab_supported{autobrightness_algorithm->init(event_loop)}, event_loop{"Backlight"}, brightness_handler{null_handler}, dim_brightness{dim_brightness_percent(device_config)}, normal_brightness{normal_brightness_percent(device_config)}, user_normal_brightness{normal_brightness}, average_time_passed{0}, active_brightness_type{ActiveBrightnessType::off}, ab_active{false} { if (ab_supported) { ab_handler_registration = autobrightness_algorithm->register_autobrightness_handler( [this] (double brightness) { if (ab_active) { this->log->logDebug(log_tag, "new_autobrightness_value(%.2f)", brightness); normal_brightness = brightness; if (active_brightness_type == ActiveBrightnessType::normal) { transition_to_brightness_value(normal_brightness, TransitionSpeed::slow); } } }); light_handler_registration = light_sensor->register_light_handler( [this] (double light) { event_loop.enqueue( [this, light] { this->autobrightness_algorithm->new_light_value(light); }); }); } } void repowerd::BacklightBrightnessControl::disable_autobrightness() { if (!ab_supported) return; event_loop.enqueue( [this] { if (ab_active) { autobrightness_algorithm->stop(); light_sensor->disable_light_events(); normal_brightness = user_normal_brightness; ab_active = false; if (active_brightness_type == ActiveBrightnessType::normal) transition_to_brightness_value(normal_brightness, TransitionSpeed::slow); } }).get(); } void repowerd::BacklightBrightnessControl::enable_autobrightness() { if (!ab_supported) return; event_loop.enqueue( [this] { if (!ab_active) { if (active_brightness_type == ActiveBrightnessType::normal) { autobrightness_algorithm->start(); light_sensor->enable_light_events(); } ab_active = true; } }).get(); } void repowerd::BacklightBrightnessControl::set_dim_brightness() { event_loop.enqueue( [this] { bool should_transition = true; auto const backlight_brightness = get_brightness_value(); if (backlight_brightness > 0.0 && backlight_brightness < dim_brightness) { should_transition = false; } if (should_transition) transition_to_brightness_value(dim_brightness, TransitionSpeed::normal); active_brightness_type = ActiveBrightnessType::dim; }).get(); } void repowerd::BacklightBrightnessControl::set_normal_brightness() { event_loop.enqueue( [this] { if (ab_active && active_brightness_type == ActiveBrightnessType::off) { if (normal_before_display_on_autobrightness) transition_to_brightness_value(normal_brightness, TransitionSpeed::normal); autobrightness_algorithm->start(); light_sensor->enable_light_events(); } else { transition_to_brightness_value(normal_brightness, TransitionSpeed::normal); } active_brightness_type = ActiveBrightnessType::normal; }).get(); } void repowerd::BacklightBrightnessControl::set_normal_brightness_value(double v) { event_loop.enqueue( [this,v] { user_normal_brightness = v; if (!ab_active) normal_brightness = user_normal_brightness; if (active_brightness_type == ActiveBrightnessType::normal && !ab_active) transition_to_brightness_value(normal_brightness, TransitionSpeed::normal); }).get(); } void repowerd::BacklightBrightnessControl::set_off_brightness() { event_loop.enqueue( [this] { transition_to_brightness_value(0, TransitionSpeed::normal); active_brightness_type = ActiveBrightnessType::off; autobrightness_algorithm->stop(); light_sensor->disable_light_events(); }).get(); } repowerd::HandlerRegistration repowerd::BacklightBrightnessControl::register_brightness_handler( BrightnessHandler const& handler) { return EventLoopHandlerRegistration( event_loop, [this,&handler] { brightness_handler = handler; }, [this] { brightness_handler = null_handler; }); } void repowerd::BacklightBrightnessControl::transition_to_brightness_value( double target_brightness, TransitionSpeed transition_speed) { auto step = 0.01; auto const backlight_brightness = get_brightness_value(); auto const starting_brightness = backlight_brightness == Backlight::unknown_brightness ? target_brightness - step : backlight_brightness; auto transition_time = (transition_speed == TransitionSpeed::slow || starting_brightness == 0.0 || target_brightness == 0.0) ? 250000us : 1000us; if (starting_brightness != target_brightness) { log->logDebug(log_tag, "Transitioning brightness %.2f => %.2f transition time %lldus", starting_brightness, target_brightness, (long long int)transition_time.count()); } auto current_brightness = starting_brightness; if (current_brightness < target_brightness) { while (current_brightness < target_brightness) { current_brightness += step; if (current_brightness > target_brightness) current_brightness = target_brightness; set_brightness(target_brightness, current_brightness, step, transition_time); } } else if (current_brightness > target_brightness) { while (current_brightness > target_brightness) { current_brightness -= step; if (current_brightness < target_brightness) current_brightness = target_brightness; set_brightness(target_brightness, current_brightness, step, transition_time); } } if (starting_brightness != target_brightness) { log->logDebug(log_tag, "Transitioning brightness %.2f => %.2f done", starting_brightness, current_brightness); brightness_handler(target_brightness); } } void repowerd::BacklightBrightnessControl::set_brightness(double target_brightness, double current_brightness, double &step, std::chrono::microseconds &transition_time) { // Time passed for executing a brightness change - calculate rough average auto time_passed = set_brightness_value(current_brightness); if (average_time_passed.count() == 0) { average_time_passed = time_passed; } else { average_time_passed = (average_time_passed + time_passed) / 2; } // Remaining delta to target brightness - If this is zero, we are done auto remaining_delta = std::abs(target_brightness - current_brightness); if (remaining_delta == 0) { return; } // If the remaining transition_time is less than the time needed for a step // set the step size to the remaining brightness delta, finishing the transition immediately if (transition_time.count() <= average_time_passed.count()) { step = remaining_delta; return; } // Else if this is the initial step try to determine the necessary step size // to finish the transition in the remaining time // Update remaining transition time transition_time -= average_time_passed; if ((step == 0.01 && average_time_passed.count() == 0) || average_time_passed.count() > 0) { // Number of steps allowed to not exceed the remaining transition time auto maximum_steps = transition_time.count() / average_time_passed.count(); // New step size step = remaining_delta / maximum_steps; /* log->logDebug(log_tag, "Adjusted new step size: %.2f max steps: %lld rem delta: %.2f rem time: %lld avg time: %lld", step, (long long int)maximum_steps, remaining_delta, (long long int)transition_time.count(), (long long int)average_time_passed.count()); */ } } std::chrono::microseconds repowerd::BacklightBrightnessControl::set_brightness_value(double brightness) { auto t1 = chrono->steady_now(); backlight->set_brightness(brightness); return std::chrono::duration_cast(chrono->steady_now() - t1); } double repowerd::BacklightBrightnessControl::get_brightness_value() { return backlight->get_brightness(); } repowerd-2023.07/src/adapters/backlight_brightness_control.h000066400000000000000000000057721446034100200242060ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/brightness_control.h" #include "brightness_notification.h" #include "event_loop.h" #include #include namespace repowerd { class AutobrightnessAlgorithm; class Backlight; class Chrono; class DeviceConfig; class DeviceQuirks; class LightSensor; class Log; class BacklightBrightnessControl : public BrightnessControl, public BrightnessNotification { public: BacklightBrightnessControl( std::shared_ptr const& backlight, std::shared_ptr const& light_sensor, std::shared_ptr const& autobrightness_algorithm, std::shared_ptr const& chrono, std::shared_ptr const& log, DeviceConfig const& device_config, DeviceQuirks const& device_quirks); void disable_autobrightness() override; void enable_autobrightness() override; void set_dim_brightness() override; void set_normal_brightness() override; void set_normal_brightness_value(double) override; void set_off_brightness() override; HandlerRegistration register_brightness_handler( BrightnessHandler const& handler) override; private: enum class ActiveBrightnessType {normal, dim, off}; enum class TransitionSpeed {normal, slow}; void transition_to_brightness_value(double brightness, TransitionSpeed transition_speed); std::chrono::microseconds set_brightness_value(double brightness); void set_brightness(double target_brightness, double current_brightness, double &step, std::chrono::microseconds &transition_time); double get_brightness_value(); std::shared_ptr const backlight; std::shared_ptr const light_sensor; std::shared_ptr const autobrightness_algorithm; std::shared_ptr const chrono; std::shared_ptr const log; bool const normal_before_display_on_autobrightness; bool const ab_supported; EventLoop event_loop; HandlerRegistration light_handler_registration; HandlerRegistration ab_handler_registration; BrightnessHandler brightness_handler; double dim_brightness; double normal_brightness; double user_normal_brightness; std::chrono::microseconds average_time_passed; ActiveBrightnessType active_brightness_type; bool ab_active; }; } repowerd-2023.07/src/adapters/binder_performance_booster.cpp000066400000000000000000000143721446034100200241760ustar00rootroot00000000000000/* * Copyright © 2023 UBports Foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alfred Neumayer */ #include "binder_performance_booster.h" #include #include "src/core/log.h" namespace { char const* const log_tag = "BinderPerformanceBooster"; } repowerd::BinderPerformanceBooster::BinderPerformanceBooster( std::shared_ptr const& log) : active_interface(nullptr), log{log}, mSm(nullptr), mRemote(nullptr), mClient(nullptr), mSceneRemote(nullptr), mSceneClient(nullptr) { DeviceInfo device_info; const std::vector interfaces { &sprd_interface, &fallback_interface }; mSceneOnName = device_info.get("RepowerdPowerHalSceneOnName", ""); mSceneOffName = device_info.get("RepowerdPowerHalSceneOffName", ""); for (const auto interface : interfaces) { mSm = gbinder_servicemanager_new(interface->device.c_str()); if (!mSm) { continue; } // Try device-specific HALs first mRemote = gbinder_servicemanager_get_service_sync(mSm, interface->fqname.c_str(), NULL); if (!mRemote) { gbinder_servicemanager_unref(mSm); continue; } mClient = gbinder_client_new(mRemote, interface->interface.c_str()); if (!mClient) { gbinder_remote_object_unref(mRemote); gbinder_servicemanager_unref(mSm); continue; } // Initialize optional scene functionality if (!interface->scene_interface.empty() && !interface->scene_fqname.empty()) { // Try exercising device-specific HALs functionality mSceneRemote = gbinder_servicemanager_get_service_sync(mSm, interface->scene_fqname.c_str(), NULL); if (mSceneRemote) { mSceneClient = gbinder_client_new(mSceneRemote, interface->scene_interface.c_str()); } if (!mSceneClient) { gbinder_remote_object_unref(mSceneRemote); } } active_interface = interface; break; } if (!active_interface) { log->log(log_tag, "No PowerHAL interface found"); } } repowerd::BinderPerformanceBooster::~BinderPerformanceBooster() { if (mSceneClient) { gbinder_client_unref(mSceneClient); mSceneClient = nullptr; } if (mClient) { gbinder_client_unref(mClient); mClient = nullptr; } if (mSceneRemote) { gbinder_remote_object_unref(mSceneRemote); mSceneRemote = nullptr; } if (mRemote) { gbinder_remote_object_unref(mRemote); mRemote = nullptr; } if (mSm) { gbinder_servicemanager_unref(mSm); mSm = nullptr; } } void repowerd::BinderPerformanceBooster::set_interactive(const bool enabled) { if (!mClient) return; int status; GBinderLocalRequest *req = gbinder_client_new_request(mClient); GBinderRemoteReply *reply; GBinderWriter writer; gbinder_local_request_init_writer(req, &writer); gbinder_writer_append_bool(&writer, enabled); reply = gbinder_client_transact_sync_reply(mClient, 1 /* setInteractive */, req, &status); if (reply) gbinder_remote_reply_unref(reply); gbinder_local_request_unref(req); } void repowerd::BinderPerformanceBooster::set_scenario(const HalPowerHint hint, const bool enabled) { if (!mClient) return; int status; GBinderLocalRequest *req = gbinder_client_new_request(mClient); GBinderRemoteReply *reply; GBinderWriter writer; gbinder_local_request_init_writer(req, &writer); gbinder_writer_append_int32(&writer, static_cast(hint)); gbinder_writer_append_int32(&writer, enabled ? 1 : 0); reply = gbinder_client_transact_sync_reply(mClient, 2 /* powerHint */, req, &status); if (reply) gbinder_remote_reply_unref(reply); gbinder_local_request_unref(req); } void repowerd::BinderPerformanceBooster::acquire_power_scene(const std::string& name) { if (!mSceneClient || name.empty()) return; GBinderLocalRequest *req = gbinder_client_new_request(mSceneClient); GBinderWriter writer; gbinder_local_request_init_writer(req, &writer); gbinder_writer_append_string8(&writer, "repowerd"); gbinder_writer_append_string8(&writer, name.c_str()); gbinder_client_transact_sync_oneway(mSceneClient, active_interface->scene_acquire_method, req); gbinder_local_request_unref(req); } void repowerd::BinderPerformanceBooster::release_power_scene(const std::string& name) { if (!mSceneClient || name.empty()) return; GBinderLocalRequest *req = gbinder_client_new_request(mSceneClient); GBinderWriter writer; gbinder_local_request_init_writer(req, &writer); gbinder_writer_append_string8(&writer, name.c_str()); gbinder_client_transact_sync_oneway(mSceneClient, active_interface->scene_release_method, req); gbinder_local_request_unref(req); } void repowerd::BinderPerformanceBooster::enable_interactive_mode() { log->log(log_tag, "enable_interactive_mode()"); set_interactive(true); set_scenario(LOW_POWER, false); set_scenario(SUSTAINED_PERFORMANCE, true); release_power_scene(mSceneOffName); acquire_power_scene(mSceneOnName); } void repowerd::BinderPerformanceBooster::disable_interactive_mode() { log->log(log_tag, "disable_interactive_mode()"); set_interactive(false); set_scenario(SUSTAINED_PERFORMANCE, false); set_scenario(LOW_POWER, true); release_power_scene(mSceneOnName); acquire_power_scene(mSceneOffName); } repowerd-2023.07/src/adapters/binder_performance_booster.h000066400000000000000000000053331446034100200236400ustar00rootroot00000000000000/* * Copyright © 2023 UBports Foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alfred Neumayer */ #pragma once #include "src/core/performance_booster.h" #include #include #include #include #include #define BINDER_UNISOC_SERVICE_IFACE "vendor.sprd.hardware.power@4.0::IPower" #define BINDER_UNISOC_SERVICE_FQNAME BINDER_UNISOC_SERVICE_IFACE "/default" namespace repowerd { class Log; class BinderPerformanceBooster : public PerformanceBooster { public: BinderPerformanceBooster(std::shared_ptr const& log); ~BinderPerformanceBooster(); void enable_interactive_mode() override; void disable_interactive_mode() override; private: struct PowerHalInterface { std::string device; std::string interface; std::string fqname; std::string scene_interface; std::string scene_fqname; int scene_acquire_method; int scene_release_method; }; enum HalPowerHint { INTERACTION = 0x00000002, LOW_POWER = 0x00000005, SUSTAINED_PERFORMANCE = 0x00000006 }; PowerHalInterface sprd_interface { "/dev/hwbinder", "android.hardware.power@1.0::IPower", "android.hardware.power@1.0::IPower/default", "vendor.sprd.hardware.power@4.0::IPower", "vendor.sprd.hardware.power@4.0::IPower/default", 11, 12 }; PowerHalInterface fallback_interface { "/dev/hwbinder", "android.hardware.power@1.0::IPower", "android.hardware.power@1.0::IPower/default", "", "", 0, 0 }; PowerHalInterface* active_interface; void set_interactive(const bool enable); void set_scenario(const HalPowerHint hint, const bool enable); void acquire_power_scene(const std::string& name); void release_power_scene(const std::string& name); std::string mSceneOnName; std::string mSceneOffName; std::shared_ptr const log; GBinderServiceManager *mSm; GBinderRemoteObject *mRemote; GBinderClient *mClient; GBinderRemoteObject *mSceneRemote; GBinderClient *mSceneClient; }; } repowerd-2023.07/src/adapters/brightness_notification.h000066400000000000000000000023611446034100200231730ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/handler_registration.h" #include namespace repowerd { using BrightnessHandler = std::function; class BrightnessNotification { public: virtual ~BrightnessNotification() = default; virtual HandlerRegistration register_brightness_handler( BrightnessHandler const& handler) = 0; protected: BrightnessNotification() = default; BrightnessNotification(BrightnessNotification const&) = delete; BrightnessNotification& operator=(BrightnessNotification const&) = delete; }; } repowerd-2023.07/src/adapters/brightness_params.cpp000066400000000000000000000033121446034100200223200ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "brightness_params.h" #include "device_config.h" int string_to_int(std::string const& value, int default_value) { try { return std::stoi(value); } catch (...) { return default_value; } } repowerd::BrightnessParams repowerd::BrightnessParams::from_device_config( DeviceConfig const& device_config) { auto dim_str = device_config.get("screenBrightnessDim", "10"); auto min_str = device_config.get("screenBrightnessSettingMinimum", "10"); auto max_str = device_config.get("screenBrightnessSettingMaximum", "255"); auto default_str = device_config.get("screenBrightnessSettingDefault", "102"); auto ab_str = device_config.get("automatic_brightness_available", "false"); BrightnessParams params; params.dim_value = string_to_int(dim_str, 10); params.min_value = string_to_int(min_str, 10); params.max_value = string_to_int(max_str, 255); params.default_value = string_to_int(default_str, 102); params.autobrightness_supported = (ab_str == "true"); return params; } repowerd-2023.07/src/adapters/brightness_params.h000066400000000000000000000017221446034100200217700ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { class DeviceConfig; struct BrightnessParams { static BrightnessParams from_device_config(DeviceConfig const&); int dim_value; int min_value; int max_value; int default_value; bool autobrightness_supported; }; } repowerd-2023.07/src/adapters/chrono.h000066400000000000000000000020561446034100200175460ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { class Chrono { public: virtual ~Chrono() = default; virtual void sleep_for(std::chrono::nanoseconds t) = 0; virtual std::chrono::steady_clock::time_point steady_now() = 0; protected: Chrono() = default; Chrono(Chrono const&) = delete; Chrono& operator=(Chrono const&) = delete; }; } repowerd-2023.07/src/adapters/console_log.cpp000066400000000000000000000033411446034100200211120ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "console_log.h" #include #include #include #include repowerd::ConsoleLog::ConsoleLog(repowerd::LogLevel threshold) : repowerd::Log::Log(threshold) { } void repowerd::ConsoleLog::logOutput(repowerd::LogLevel level, char const* tag, char const* format, va_list ap) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); char now[32]; auto const offset = strftime(now, sizeof(now), "%F %T", localtime(&ts.tv_sec)); snprintf(now + offset, sizeof(now) - offset, ".%06ld", ts.tv_nsec / 1000); std::string format_str; format_str += "["; format_str += now; format_str += "] "; format_str += tag; format_str += ": "; switch (level) { case LogLevel::Warning: format_str += "WARNING"; break; case LogLevel::Info: format_str += "INFO"; break; default: format_str += "DEBUG"; } format_str += ": "; format_str += format; format_str += "\n"; vprintf(format_str.c_str(), ap); fflush(stdout); } repowerd-2023.07/src/adapters/console_log.h000066400000000000000000000016571446034100200205670ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/log.h" namespace repowerd { class ConsoleLog : public Log { public: ConsoleLog(LogLevel threshold); void logOutput(LogLevel level, char const* tag, char const* format, va_list ap) override; }; } repowerd-2023.07/src/adapters/dbus_connection_handle.cpp000066400000000000000000000054501446034100200233010ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_connection_handle.h" #include "scoped_g_error.h" #include #include repowerd::DBusConnectionHandle::DBusConnectionHandle(std::string const& address) { repowerd::ScopedGError error; connection = g_dbus_connection_new_for_address_sync( address.c_str(), GDBusConnectionFlags( G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), nullptr, nullptr, error); if (!connection) { throw std::runtime_error( "Failed to connect to DBus bus with address '" + address + "': " + error.message_str()); } } repowerd::DBusConnectionHandle::~DBusConnectionHandle() { g_dbus_connection_close_sync(connection, nullptr, nullptr); } void repowerd::DBusConnectionHandle::request_name(char const* name) const { static constexpr uint32_t DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x4; static constexpr uint32_t DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 0x1; repowerd::ScopedGError error; int const timeout_default = -1; auto const null_cancellable = nullptr; auto result = g_dbus_connection_call_sync( connection, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName", g_variant_new("(su)", name, DBUS_NAME_FLAG_DO_NOT_QUEUE), G_VARIANT_TYPE("(u)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { throw std::runtime_error( "Failed to request DBus name '" + std::string{name} + "': " + error.message_str()); } uint32_t request_name_reply{0}; g_variant_get(result, "(u)", &request_name_reply); g_variant_unref(result); if (request_name_reply != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { throw std::runtime_error( "Failed to become the primary owner of DBus name '" + std::string{name} + "'"); } } repowerd::DBusConnectionHandle::operator GDBusConnection*() const { return connection; } repowerd-2023.07/src/adapters/dbus_connection_handle.h000066400000000000000000000022321446034100200227410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class DBusConnectionHandle { public: DBusConnectionHandle(std::string const& address); ~DBusConnectionHandle(); void request_name(char const* name) const; operator GDBusConnection*() const; private: DBusConnectionHandle(DBusConnectionHandle const&) = delete; DBusConnectionHandle& operator=(DBusConnectionHandle const&) = delete; GDBusConnection* connection; }; } repowerd-2023.07/src/adapters/dbus_event_loop.cpp000066400000000000000000000137571446034100200220120ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_event_loop.h" #include "event_loop_handler_registration.h" #include "scoped_g_error.h" namespace { // Send a synchronous request to ensure all previous requests have // reached the dbus daemon void repowerd_g_dbus_connection_wait_for_requests(GDBusConnection* connection) { int const timeout_default = -1; auto const null_cancellable = nullptr; auto const null_args = nullptr; auto const null_return_args_types = nullptr; auto const null_error = nullptr; auto result = g_dbus_connection_call_sync( connection, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetId", null_args, null_return_args_types, G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, null_error); g_variant_unref(result); } } repowerd::HandlerRegistration repowerd::DBusEventLoop::register_object_handler( GDBusConnection* dbus_connection, char const* dbus_path, char const* introspection_xml, DBusEventLoopMethodCallHandler const& handler) { struct ObjectContext { static void static_call( GDBusConnection* connection, char const* sender, char const* object_path, char const* interface_name, char const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation, ObjectContext* ctx) { ctx->handler( connection, sender, object_path, interface_name, method_name, parameters, invocation); } static void static_destroy(ObjectContext* ctx) { delete ctx; } DBusEventLoopMethodCallHandler const handler; }; unsigned int registration_id = 0; auto done = enqueue( [&] { auto const introspection_data = g_dbus_node_info_new_for_xml( introspection_xml, NULL); GDBusInterfaceVTable interface_vtable; interface_vtable.method_call = reinterpret_cast(&ObjectContext::static_call); interface_vtable.get_property = nullptr; interface_vtable.set_property = nullptr; ScopedGError error; registration_id = g_dbus_connection_register_object( dbus_connection, dbus_path, introspection_data->interfaces[0], &interface_vtable, new ObjectContext{handler}, reinterpret_cast(&ObjectContext::static_destroy), error); g_dbus_node_info_unref(introspection_data); if (error.is_set()) { throw std::runtime_error{ "Failed to register DBus object '" + std::string{dbus_path} + "': " + error.message_str()}; } }); done.wait(); // g_dbus_connection_register_object() is not synchronous, so wait for // the registration (really a DBus AddMatch request) to be processed // by the server repowerd_g_dbus_connection_wait_for_requests(dbus_connection); return EventLoopHandlerRegistration( *this, [dbus_connection,registration_id] { g_dbus_connection_unregister_object( dbus_connection, registration_id); }); } repowerd::HandlerRegistration repowerd::DBusEventLoop::register_signal_handler( GDBusConnection* dbus_connection, char const* dbus_sender, char const* dbus_interface, char const* dbus_member, char const* dbus_path, DBusEventLoopSignalHandler const& handler) { struct SignalContext { static void static_call( GDBusConnection* connection, char const* sender, char const* object_path, char const* interface_name, char const* signal_name, GVariant* parameters, SignalContext* ctx) { ctx->handler( connection, sender, object_path, interface_name, signal_name, parameters); } static void static_destroy(SignalContext* ctx) { delete ctx; } DBusEventLoopSignalHandler const handler; }; unsigned int registration_id = 0; auto done = enqueue( [&] { registration_id = g_dbus_connection_signal_subscribe( dbus_connection, dbus_sender, dbus_interface, dbus_member, dbus_path, nullptr, G_DBUS_SIGNAL_FLAGS_NONE, reinterpret_cast(&SignalContext::static_call), new SignalContext{handler}, reinterpret_cast(&SignalContext::static_destroy)); }); done.wait(); // g_dbus_connection_signal_subscribe() is not synchronous, so wait for // the subscription (really a DBus AddMatch request) to be processed // by the server repowerd_g_dbus_connection_wait_for_requests(dbus_connection); return EventLoopHandlerRegistration( *this, [dbus_connection,registration_id] { g_dbus_connection_signal_unsubscribe( dbus_connection, registration_id); }); } repowerd-2023.07/src/adapters/dbus_event_loop.h000066400000000000000000000040231446034100200214410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "event_loop.h" #include "src/core/handler_registration.h" #include namespace repowerd { using DBusEventLoopMethodCallHandler = std::function< void( GDBusConnection* connection, char const* sender, char const* object_path, char const* interface_name, char const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation)>; using DBusEventLoopSignalHandler = std::function< void( GDBusConnection* connection, char const* sender, char const* object_path, char const* interface_name, char const* signal_name, GVariant* parameters)>; class DBusEventLoop : public EventLoop { public: using EventLoop::EventLoop; repowerd::HandlerRegistration register_object_handler( GDBusConnection* dbus_connection, char const* dbus_path, char const* introspection_xml, DBusEventLoopMethodCallHandler const& handler); repowerd::HandlerRegistration register_signal_handler( GDBusConnection* dbus_connection, char const* dbus_sender, char const* dbus_interface, char const* dbus_member, char const* dbus_path, DBusEventLoopSignalHandler const& handler); }; } repowerd-2023.07/src/adapters/dbus_message_handle.cpp000066400000000000000000000030271446034100200225640ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_message_handle.h" #include repowerd::DBusMessageHandle::DBusMessageHandle(GDBusMessage* message) : message{message} { } repowerd::DBusMessageHandle::DBusMessageHandle(GDBusMessage* message, GVariant* params) : message{message} { if (!message) throw std::runtime_error("Failed to create DBusMessageHandle with invalid dbus message"); g_dbus_message_set_body(message, params); } repowerd::DBusMessageHandle::DBusMessageHandle(DBusMessageHandle&& other) noexcept : message{other.message} { other.message = nullptr; } repowerd::DBusMessageHandle::~DBusMessageHandle() { if (message) g_object_unref(message); } repowerd::DBusMessageHandle::operator GDBusMessage*() const { return message; } repowerd::DBusMessageHandle::operator bool() const { return message != nullptr; } repowerd-2023.07/src/adapters/dbus_message_handle.h000066400000000000000000000023031446034100200222250ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { class DBusMessageHandle { public: DBusMessageHandle(GDBusMessage* message); DBusMessageHandle(GDBusMessage* message, GVariant* params); DBusMessageHandle(DBusMessageHandle&&) noexcept; ~DBusMessageHandle(); operator GDBusMessage*() const; operator bool() const; private: DBusMessageHandle(DBusMessageHandle const&) = delete; DBusMessageHandle& operator=(DBusMessageHandle const&) = delete; GDBusMessage* message; }; } repowerd-2023.07/src/adapters/default_state_machine_options.cpp000066400000000000000000000074261446034100200247020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "default_state_machine_options.h" #include "src/core/log.h" #include "src/core/infinite_timeout.h" #include "device_info.h" using namespace std::chrono_literals; char const* const log_tag = "DefaultStateMachineOptions"; repowerd::DefaultStateMachineOptions::DefaultStateMachineOptions( repowerd::Log& log, std::shared_ptr const& device_info_) : device_info(device_info_) { log.logDebug(log_tag, "DeviceName: %s", device_info->name().c_str()); log.logDebug(log_tag, "Option: notification_expiration_timeout=%lld", static_cast(notification_expiration_timeout().count())); log.logDebug(log_tag, "Option: power_button_long_press_timeout=%lld", static_cast(power_button_long_press_timeout().count())); log.logDebug(log_tag, "Option: treat_power_button_as_user_activity=%s", treat_power_button_as_user_activity() ? "true" : "false"); log.logDebug(log_tag, "Option: turn_on_display_at_startup=%s", turn_on_display_at_startup() ? "true" : "false"); log.logDebug(log_tag, "Option: user_inactivity_normal_display_dim_duration=%lld", static_cast(user_inactivity_normal_display_dim_duration().count())); log.logDebug(log_tag, "Option: user_inactivity_normal_display_off_timeout=%lld", static_cast(user_inactivity_normal_display_off_timeout().count())); log.logDebug(log_tag, "Option: user_inactivity_normal_suspend_timeout=%lld", static_cast(user_inactivity_normal_suspend_timeout().count())); log.logDebug(log_tag, "Option: user_inactivity_post_notification_display_off_timeout=%lld", static_cast(user_inactivity_post_notification_display_off_timeout().count())); log.logDebug(log_tag, "Option: user_inactivity_reduced_display_off_timeout=%lld", static_cast(user_inactivity_reduced_display_off_timeout().count())); } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::notification_expiration_timeout() const { return 60s; } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::power_button_long_press_timeout() const { return 2s; } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::user_inactivity_normal_display_dim_duration() const { return 10s; } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::user_inactivity_normal_display_off_timeout() const { return 60s; } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::user_inactivity_normal_suspend_timeout() const { return repowerd::infinite_timeout; } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::user_inactivity_post_notification_display_off_timeout() const { return 5s; } std::chrono::milliseconds repowerd::DefaultStateMachineOptions::user_inactivity_reduced_display_off_timeout() const { return 10s; } bool repowerd::DefaultStateMachineOptions::treat_power_button_as_user_activity() const { return device_info->is_desktop(); } bool repowerd::DefaultStateMachineOptions::turn_on_display_at_startup() const { return true; } repowerd-2023.07/src/adapters/default_state_machine_options.h000066400000000000000000000034301446034100200243360ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/state_machine_options.h" #include #include namespace repowerd { class Log; class DeviceInfo; class DefaultStateMachineOptions : public StateMachineOptions { public: DefaultStateMachineOptions(Log& log, std::shared_ptr const& deviceInfo); std::chrono::milliseconds notification_expiration_timeout() const override; std::chrono::milliseconds power_button_long_press_timeout() const override; std::chrono::milliseconds user_inactivity_normal_display_dim_duration() const override; std::chrono::milliseconds user_inactivity_normal_display_off_timeout() const override; std::chrono::milliseconds user_inactivity_normal_suspend_timeout() const override; std::chrono::milliseconds user_inactivity_post_notification_display_off_timeout() const override; std::chrono::milliseconds user_inactivity_reduced_display_off_timeout() const override; bool treat_power_button_as_user_activity() const override; bool turn_on_display_at_startup() const override; private: std::shared_ptr device_info; }; } repowerd-2023.07/src/adapters/dev_alarm_wakeup_service.cpp000066400000000000000000000117501446034100200236400ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dev_alarm_wakeup_service.h" #include "filesystem.h" #include #include #include #include #include namespace { auto null_handler = [](auto){}; void ioctl_or_throw( repowerd::Filesystem& fs, int fd, unsigned long request, void* args, char const* error_msg) { int retval; do { retval = fs.ioctl(fd, request, args); } while (retval < 0 && errno == EINTR); if (retval < 0) throw std::system_error{errno, std::system_category(), error_msg}; } timespec to_timespec(std::chrono::system_clock::time_point const& tp) { auto d = tp.time_since_epoch(); auto const sec = std::chrono::duration_cast(d); timespec ts; ts.tv_sec = sec.count(); ts.tv_nsec = std::chrono::duration_cast(d - sec).count(); return ts; } } repowerd::DevAlarmWakeupService::DevAlarmWakeupService( std::shared_ptr const& filesystem) : filesystem{filesystem}, dev_alarm_fd{filesystem->open("/dev/alarm", O_RDWR)}, running{true}, cookie_pool{1}, wakeup_handler{null_handler} { if (dev_alarm_fd == -1) throw std::system_error{errno, std::system_category(), "Failed to open /dev/alarm"}; reset_hardware_alarm(); wakeup_thread = std::thread( [this] { std::unique_lock lock{wakeup_mutex}; while (running) { lock.unlock(); ioctl_or_throw( *this->filesystem, dev_alarm_fd, ANDROID_ALARM_WAIT, nullptr, "Failed to wait for alarm on /dev/alarm"); lock.lock(); if (running && !wakeups.empty()) { auto const wakeup = *wakeups.begin(); cookie_pool.remove(std::stoull(wakeup.second)); wakeups.erase(wakeups.begin()); auto const handler = wakeup_handler; lock.unlock(); handler(wakeup.second); lock.lock(); } reset_hardware_alarm(); } }); } repowerd::DevAlarmWakeupService::~DevAlarmWakeupService() { { std::lock_guard lock{wakeup_mutex}; running = false; reset_hardware_alarm(); } wakeup_thread.join(); } std::string repowerd::DevAlarmWakeupService::schedule_wakeup_at( std::chrono::system_clock::time_point tp) { std::lock_guard lock{wakeup_mutex}; auto const cookie = std::to_string(cookie_pool.generate()); wakeups.insert({tp, cookie}); reset_hardware_alarm(); return cookie; } void repowerd::DevAlarmWakeupService::cancel_wakeup(std::string const& cookie) { std::lock_guard lock{wakeup_mutex}; for (auto iter = wakeups.begin(); iter != wakeups.end(); ++iter) { if (iter->second == cookie) { cookie_pool.remove(std::stoull(cookie)); wakeups.erase(iter); break; } } reset_hardware_alarm(); } repowerd::HandlerRegistration repowerd::DevAlarmWakeupService::register_wakeup_handler( WakeupHandler const& handler) { std::lock_guard lock{wakeup_mutex}; wakeup_handler = handler; return repowerd::HandlerRegistration{ [this] { std::lock_guard lock{wakeup_mutex}; wakeup_handler = null_handler; }}; } unsigned int repowerd::DevAlarmWakeupService::num_stored_elements() { std::lock_guard lock{wakeup_mutex}; return cookie_pool.size() + wakeups.size(); } void repowerd::DevAlarmWakeupService::reset_hardware_alarm() { using std::chrono::system_clock; timespec next_wakeup; if (running) { if (wakeups.empty()) { next_wakeup = to_timespec(system_clock::now() + std::chrono::hours(24 * 30)); } else { next_wakeup = to_timespec(wakeups.begin()->first); } } else { next_wakeup = to_timespec(system_clock::time_point{}); } ioctl_or_throw( *filesystem, dev_alarm_fd, ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP), &next_wakeup, "Failed to set alarm on /dev/alarm"); } repowerd-2023.07/src/adapters/dev_alarm_wakeup_service.h000066400000000000000000000032741446034100200233070ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "wakeup_service.h" #include "fd.h" #include "unique_random_pool.h" #include #include #include namespace repowerd { class Filesystem; class DevAlarmWakeupService : public WakeupService { public: DevAlarmWakeupService(std::shared_ptr const& filesystem); ~DevAlarmWakeupService(); std::string schedule_wakeup_at(std::chrono::system_clock::time_point tp) override; void cancel_wakeup(std::string const& cookie) override; HandlerRegistration register_wakeup_handler( WakeupHandler const& handler) override; // For testing only unsigned int num_stored_elements(); private: void reset_hardware_alarm(); std::shared_ptr const filesystem; Fd const dev_alarm_fd; std::thread wakeup_thread; std::mutex wakeup_mutex; bool running; UniqueRandomPool cookie_pool; WakeupHandler wakeup_handler; std::multimap wakeups; }; } repowerd-2023.07/src/adapters/device_config.h000066400000000000000000000021021446034100200210320ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { class DeviceConfig { public: virtual ~DeviceConfig() = default; virtual std::string get( std::string const& name, std::string const& default_value) const = 0; protected: DeviceConfig() = default; DeviceConfig(DeviceConfig const&) = delete; DeviceConfig& operator=(DeviceConfig const&) = delete; }; } repowerd-2023.07/src/adapters/device_info.h000066400000000000000000000020241446034100200205230ustar00rootroot00000000000000/* * Copyright © 2022 UBports Foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #pragma once #include #include namespace repowerd { class DeviceInfo { public: virtual ~DeviceInfo() = default; virtual std::string name() = 0; virtual bool is_desktop() = 0; protected: DeviceInfo() = default; DeviceInfo(DeviceInfo const&) = delete; DeviceInfo& operator=(DeviceInfo const&) = delete; }; }repowerd-2023.07/src/adapters/device_quirks.h000066400000000000000000000024651446034100200211170ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { class DeviceQuirks { public: enum class ProximityEventType {near, far}; virtual ~DeviceQuirks() = default; virtual std::chrono::milliseconds synthetic_initial_proximity_event_delay() const = 0; virtual ProximityEventType synthetic_initial_proximity_event_type() const = 0; virtual bool normal_before_display_on_autobrightness() const = 0; virtual bool ignore_session_deactivation() const = 0; protected: DeviceQuirks() = default; DeviceQuirks(DeviceQuirks const&) = delete; DeviceQuirks& operator=(DeviceQuirks const&) = delete; }; } repowerd-2023.07/src/adapters/event_loop.cpp000066400000000000000000000132631446034100200207650ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "event_loop.h" #include #include namespace { void set_thread_name(std::thread& thread, std::string const& name) { static size_t const max_name_len = 15; auto const proper_name = name.substr(0, max_name_len); pthread_setname_np(thread.native_handle(), proper_name.c_str()); } struct GSourceContext { GSourceContext(std::function const& callback) : callback{callback} { } static gboolean static_call(GSourceContext* ctx) { try { ctx->callback(); ctx->done.set_value(); } catch (...) { ctx->done.set_exception(std::current_exception()); } return G_SOURCE_REMOVE; } static void static_destroy(GSourceContext* ctx) { delete ctx; } std::function const callback; std::promise done; }; struct GSourceFdContext { GSourceFdContext(std::function const& callback) : callback{callback} { } static gboolean static_call(int, GIOCondition, GSourceFdContext* ctx) { try { ctx->callback(); } catch (...) { } return G_SOURCE_CONTINUE; } static void static_destroy(GSourceFdContext* ctx) { delete ctx; } std::function const callback; }; } repowerd::EventLoop::EventLoop(std::string const& name) : main_context{g_main_context_new()}, main_loop{g_main_loop_new(main_context, FALSE)} { loop_thread = std::thread{ [this] { g_main_context_push_thread_default(main_context); g_main_loop_run(main_loop); }}; set_thread_name(loop_thread, name); enqueue([]{}).wait(); } repowerd::EventLoop::~EventLoop() { stop(); } void repowerd::EventLoop::stop() { if (main_loop) g_main_loop_quit(main_loop); if (loop_thread.joinable()) loop_thread.join(); if (main_loop) { g_main_loop_unref(main_loop); main_loop = nullptr; } if (main_context) { g_main_context_unref(main_context); main_context = nullptr; } } std::future repowerd::EventLoop::enqueue(std::function const& callback) { auto const gsource = g_idle_source_new(); auto const ctx = new GSourceContext{callback}; g_source_set_callback( gsource, reinterpret_cast(&GSourceContext::static_call), ctx, reinterpret_cast(&GSourceContext::static_destroy)); auto future = ctx->done.get_future(); g_source_attach(gsource, main_context); g_source_unref(gsource); return future; } std::future repowerd::EventLoop::schedule_in( std::chrono::milliseconds timeout, std::function const& callback) { auto const gsource = g_timeout_source_new(timeout.count()); auto const ctx = new GSourceContext{callback}; g_source_set_callback( gsource, reinterpret_cast(&GSourceContext::static_call), ctx, reinterpret_cast(&GSourceContext::static_destroy)); auto future = ctx->done.get_future(); g_source_attach(gsource, main_context); g_source_unref(gsource); return future; } void repowerd::EventLoop::schedule_with_cancellation_in( std::chrono::milliseconds timeout, std::function const& callback, std::function const& cancellation_ready) { auto const gsource = g_timeout_source_new(timeout.count()); auto const ctx = new GSourceContext{callback}; g_source_set_callback( gsource, reinterpret_cast(&GSourceContext::static_call), ctx, reinterpret_cast(&GSourceContext::static_destroy)); auto const cancellation = [this, gsource] { g_source_destroy(gsource); g_source_unref(gsource); }; enqueue( [cancellation, cancellation_ready] { cancellation_ready(cancellation); }); g_source_attach(gsource, main_context); } void repowerd::EventLoop::watch_fd( int fd, std::function const& callback) { auto const gsource = g_unix_fd_source_new(fd, G_IO_IN); auto const ctx = new GSourceFdContext{callback}; #pragma GCC diagnostic push // For casting GSourceFdContext::static_call from GUnixFDSourceFunc to // GSourceFunc. GLib itself does this in g_unix_fd_add_full() [1]. I don't // understand why it's done this way. // [1] https://gitlab.gnome.org/GNOME/glib/-/blob/0c8740dc838263008da7be68192065ae7e935bed/glib/glib-unix.c#L392 #pragma GCC diagnostic ignored "-Wcast-function-type" g_source_set_callback( gsource, reinterpret_cast(&GSourceFdContext::static_call), ctx, reinterpret_cast(&GSourceFdContext::static_destroy)); #pragma GCC diagnostic pop g_source_attach(gsource, main_context); g_source_unref(gsource); } repowerd-2023.07/src/adapters/event_loop.h000066400000000000000000000030221446034100200204220ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include #include #include #include namespace repowerd { using EventLoopCancellation = std::function; class EventLoop { public: EventLoop(std::string const& name); ~EventLoop(); void stop(); std::future enqueue(std::function const& callback); std::future schedule_in( std::chrono::milliseconds, std::function const& callback); void schedule_with_cancellation_in( std::chrono::milliseconds, std::function const& callback, std::function const& cancellation_ready); void watch_fd(int fd, std::function const& callback); protected: std::thread loop_thread; GMainContext* main_context; GMainLoop* main_loop; }; } repowerd-2023.07/src/adapters/event_loop_handler_registration.h000066400000000000000000000026051446034100200247170ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/handler_registration.h" #include "event_loop.h" namespace repowerd { class EventLoopHandlerRegistration : public HandlerRegistration { public: EventLoopHandlerRegistration( repowerd::EventLoop& loop, std::function const& register_func, std::function const& unregister) : HandlerRegistration{[&, unregister] { loop.enqueue(unregister).wait(); }} { loop.enqueue(register_func).wait(); } EventLoopHandlerRegistration( repowerd::EventLoop& loop, std::function const& unregister) : HandlerRegistration{[&, unregister] { loop.enqueue(unregister).wait(); }} { } }; } repowerd-2023.07/src/adapters/event_loop_timer.cpp000066400000000000000000000047471446034100200221740ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "event_loop_timer.h" #include "event_loop_handler_registration.h" namespace { auto const null_handler = [](auto){}; } repowerd::EventLoopTimer::EventLoopTimer() : event_loop{"Timer"}, alarm_handler{null_handler}, next_alarm_id{1} { } repowerd::EventLoopTimer::~EventLoopTimer() { event_loop.stop(); for (auto const& alarm : alarms) alarm.second(); } repowerd::HandlerRegistration repowerd::EventLoopTimer::register_alarm_handler( AlarmHandler const& handler) { return EventLoopHandlerRegistration{ event_loop, [this, &handler] { alarm_handler = handler; }, [this] { alarm_handler = null_handler; }}; } repowerd::AlarmId repowerd::EventLoopTimer::schedule_alarm_in( std::chrono::milliseconds t) { repowerd::AlarmId alarm_id; { std::lock_guard lock{alarms_mutex}; alarm_id = next_alarm_id++; } event_loop.schedule_with_cancellation_in( t, [this, alarm_id] { alarm_handler(alarm_id); cancel_alarm_unqueued(alarm_id); }, [this, alarm_id] (EventLoopCancellation const& cancellation) { std::lock_guard lock{alarms_mutex}; alarms[alarm_id] = cancellation; }); return alarm_id; } void repowerd::EventLoopTimer::cancel_alarm(AlarmId id) { event_loop.enqueue([this,id] { cancel_alarm_unqueued(id); }).get(); } std::chrono::steady_clock::time_point repowerd::EventLoopTimer::now() { return std::chrono::steady_clock::now(); } void repowerd::EventLoopTimer::cancel_alarm_unqueued(AlarmId id) { std::lock_guard lock{alarms_mutex}; auto const iter = alarms.find(id); if (iter != alarms.end()) { iter->second(); alarms.erase(iter); } } repowerd-2023.07/src/adapters/event_loop_timer.h000066400000000000000000000026171446034100200216330ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/timer.h" #include "event_loop.h" #include #include namespace repowerd { class EventLoopTimer : public Timer { public: EventLoopTimer(); ~EventLoopTimer(); HandlerRegistration register_alarm_handler(AlarmHandler const& handler) override; AlarmId schedule_alarm_in(std::chrono::milliseconds t) override; void cancel_alarm(AlarmId id) override; std::chrono::steady_clock::time_point now() override; private: void cancel_alarm_unqueued(AlarmId id); EventLoop event_loop; AlarmHandler alarm_handler; std::mutex alarms_mutex; std::unordered_map alarms; AlarmId next_alarm_id; }; } repowerd-2023.07/src/adapters/fd.cpp000066400000000000000000000026151446034100200172030ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fd.h" #include repowerd::Fd::Fd(int fd) : fd{fd}, close_func{::close} { } repowerd::Fd::Fd(int fd, FdCloseFunc const& close_func) : fd{fd}, close_func{close_func} { } repowerd::Fd::Fd(Fd&& other) : fd{other.fd}, close_func{std::move(other.close_func)} { other.fd = -1; } repowerd::Fd& repowerd::Fd::operator=(Fd&& other) { if (&other != this) { close(); fd = other.fd; close_func = std::move(other.close_func); other.fd = -1; } return *this; } repowerd::Fd::~Fd() { close(); } repowerd::Fd::operator int() const { return fd; } void repowerd::Fd::close() const { if (fd >= 0) close_func(fd); } repowerd-2023.07/src/adapters/fd.h000066400000000000000000000021601446034100200166430ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { using FdCloseFunc = std::function; class Fd { public: Fd(int fd); Fd(int fd, FdCloseFunc const& close_func); Fd(Fd&&); Fd& operator=(Fd&&); ~Fd(); operator int() const; private: Fd(Fd const&) = delete; Fd& operator=(Fd const&) = delete; void close() const; int fd; FdCloseFunc close_func; }; } repowerd-2023.07/src/adapters/filesystem.h000066400000000000000000000027541446034100200204470ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include #include #include #include namespace repowerd { class Fd; class Filesystem { public: virtual ~Filesystem() = default; virtual bool is_regular_file(std::string const& path) const = 0; virtual std::unique_ptr istream(std::string const& path) const = 0; virtual std::unique_ptr ostream(std::string const& path) const = 0; virtual std::vector subdirs(std::string const& path) const = 0; virtual Fd open(char const* pathname, int flags) const = 0; virtual int ioctl(int fd, unsigned long request, void* args) const = 0; protected: Filesystem() = default; Filesystem(Filesystem const&) = delete; Filesystem& operator=(Filesystem const&) = delete; }; } repowerd-2023.07/src/adapters/fs_double_tap_to_wake.cpp000066400000000000000000000104221446034100200231240ustar00rootroot00000000000000/* * Copyright © 2022 UBports foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexander Martinz */ #include "fs_double_tap_to_wake.h" namespace { char const* const log_tag = "FsDoubleTapToWake"; std::vector split_value_by(std::string const& to_split, std::string const& delimiter) { std::vector parts; size_t last = 0; size_t next = 0; while ((next = to_split.find(delimiter, last)) != std::string::npos) { auto part = to_split.substr(last, next - last); parts.push_back(part); last = next + 1; } parts.push_back(to_split.substr(last)); return parts; } } repowerd::FsDoubleTapToWake::FsDoubleTapToWake( std::shared_ptr const& log, std::shared_ptr const& filesystem) : log{log}, filesystem{filesystem} { DeviceInfo device_info; auto configvalue = device_info.get("DoubleTapToWake", ""); parse_config(configvalue); } repowerd::FsDoubleTapToWake::~FsDoubleTapToWake() = default; bool repowerd::FsDoubleTapToWake::is_supported() { return !configs.empty(); } void repowerd::FsDoubleTapToWake::enable() { set_enabled(true); } void repowerd::FsDoubleTapToWake::disable() { set_enabled(false); } void repowerd::FsDoubleTapToWake::set_enabled(bool enable) { log->logDebug(log_tag, "%s DoubleTapToWake", enable ? "Enabling" : "Disabling"); for (auto const& config : configs) { if (!filesystem->is_regular_file(config.path)) { log->logWarning(log_tag, "Invalid path (%s)), skipping", config.path.c_str()); continue; } auto ostream = filesystem->ostream(config.path); *ostream << (enable ? config.enable_value : config.disable_value); ostream->flush(); } } bool repowerd::FsDoubleTapToWake::is_enabled() { bool enabled = false; for (auto const& config : configs) { if (!filesystem->is_regular_file(config.path)) { log->logWarning(log_tag, "Invalid path (%s)), skipping", config.path.c_str()); continue; } auto istream = filesystem->istream(config.path); std::string value; *istream >> value; if (value == config.enable_value) enabled = true; else return false; } log->logDebug(log_tag, "Enabled -> %s", enabled ? "true" : "false"); return enabled; } void repowerd::FsDoubleTapToWake::parse_config(std::string const& configvalue) { if (configvalue.empty()) { log->logDebug(log_tag, "No DoubleTapToWake config set"); return; } log->logDebug(log_tag, "Parsing config: %s", configvalue.c_str()); /* * Config format: /path/to/node|ON|OFF,/path/to/another/node|ON|OFF,... * Example: /proc/touchpanel/double_tap_enable|1|0,/sys/devices/platform/soc/a84000.i2c/i2c-2/2-0020/input/input1/wake_gesture|on|off */ auto const entries = split_value_by(configvalue, ","); for (auto const& entry : entries) { log->logDebug(log_tag, "Parsing entry: %s", entry.c_str()); auto const parts = split_value_by(entry, "|"); if (parts.size() != 3) { log->logWarning(log_tag, "Invalid config entry, expected (%d) but got (%zu), skipping", 3, parts.size()); continue; } if (!filesystem->is_regular_file(parts[0])) { log->logWarning(log_tag, "Invalid config path (%s)), skipping", parts[0].c_str()); continue; } FsDoubleTapToWakeConfig config; config.path = parts[0]; config.enable_value = parts[1]; config.disable_value = parts[2]; configs.push_back(config); } } repowerd-2023.07/src/adapters/fs_double_tap_to_wake.h000066400000000000000000000027371446034100200226030ustar00rootroot00000000000000/* * Copyright © 2022 UBports foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexander Martinz */ #pragma once #include "src/core/double_tap_to_wake.h" namespace repowerd { class Log; class Filesystem; struct FsDoubleTapToWakeConfig { std::string path; std::string enable_value; std::string disable_value; }; class FsDoubleTapToWake : public DoubleTapToWake { public: FsDoubleTapToWake( std::shared_ptr const& log, std::shared_ptr const& filesystem); ~FsDoubleTapToWake(); bool is_enabled() override; bool is_supported() override; void enable() override; void disable() override; protected: std::shared_ptr const log; std::shared_ptr const filesystem; std::vector configs; void parse_config(std::string const& configvalue); void set_enabled(bool) override; }; } repowerd-2023.07/src/adapters/libsuspend/000077500000000000000000000000001446034100200202525ustar00rootroot00000000000000repowerd-2023.07/src/adapters/libsuspend/CMakeLists.txt000066400000000000000000000001641446034100200230130ustar00rootroot00000000000000add_library( suspend STATIC libsuspend.c sysfs.c autosleep.c earlysuspend.c legacy.c mocksuspend.c ) repowerd-2023.07/src/adapters/libsuspend/autosleep.c000066400000000000000000000037761446034100200224340ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "common.h" #include "sysfs.h" static const char autosleep_name[] = "autosleep"; static const char autosleep_path[] = "/sys/power/autosleep"; static const char wakelock_path[] = "/sys/power/wake_lock"; static const char wakeunlock_path[] = "/sys/power/wake_unlock"; static const char mem_str[] = "mem"; static const char off_str[] = "off"; static int autosleep_enter(void) { int ret = sysfs_write(autosleep_path, mem_str, ARRAY_SIZE(mem_str) - 1); return ret < 0 ? ret : 0; } static int autosleep_exit(void) { int ret = sysfs_write(autosleep_path, off_str, ARRAY_SIZE(off_str) - 1); return ret < 0 ? ret : 0; } static int autosleep_acquire_wake_lock(const char *name) { int ret = sysfs_write(wakelock_path, name, strlen(name)); return ret < 0 ? ret : 0; } static int autosleep_release_wake_lock(const char *name) { int ret = sysfs_write(wakeunlock_path, name, strlen(name)); return ret < 0 ? ret : 0; } static const struct suspend_handler autosleep_handler = { .name = autosleep_name, .enter = autosleep_enter, .exit = autosleep_exit, .acquire_wake_lock = autosleep_acquire_wake_lock, .release_wake_lock = autosleep_release_wake_lock, }; const struct suspend_handler *autosleep_detect(void) { if (!sysfs_file_exists(autosleep_path)) return NULL; return &autosleep_handler; } repowerd-2023.07/src/adapters/libsuspend/common.h000066400000000000000000000022561446034100200217200ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SUSPENDIF_H #define SUSPENDIF_H #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) struct suspend_handler { const char *name; int (*prepare)(void); int (*enter)(void); int (*exit)(void); int (*acquire_wake_lock)(const char *); int (*release_wake_lock)(const char *); }; const struct suspend_handler *autosleep_detect(void); const struct suspend_handler *earlysuspend_detect(void); const struct suspend_handler *legacy_detect(void); const struct suspend_handler *mocksuspend_detect(void); #endif /* SUSPENDIF_H */ repowerd-2023.07/src/adapters/libsuspend/earlysuspend.c000066400000000000000000000110161446034100200231330ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "common.h" #include "sysfs.h" /* Use to suppress unused parameter warnings */ #define __unused __attribute__ ((unused)) enum fb_state { FB_SLEEP, FB_AWAKE, NUM_FB_STATES }; static enum fb_state fb_state = FB_AWAKE; static const char *fb_file_names[] = { [FB_SLEEP] = "/sys/power/wait_for_fb_sleep", [FB_AWAKE] = "/sys/power/wait_for_fb_wake" }; static pthread_t fb_monitor_thread; static pthread_mutex_t fb_state_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t fb_state_cond = PTHREAD_COND_INITIALIZER; static int wait_for_fb = 0; static const char earlysuspend_name[] = "earlysuspend"; static const char state_path[] = "/sys/power/state"; static const char wakelock_path[] = "/sys/power/wake_lock"; static const char wakeunlock_path[] = "/sys/power/wake_unlock"; static const char mem_str[] = "mem"; static const char on_str[] = "on"; static int wait_for_file(const char *fname) { int fd, ret; char buf; fd = open(fname, O_RDONLY); if (fd == -1) return -errno; do { ret = read(fd, &buf, 1); } while (ret == -1 && errno == EINTR); close(fd); return ret == -1 ? -errno : 0; } static void *fb_monitor_thread_func(__unused void *unused) { enum fb_state next_state; int ret; while (1) { next_state = fb_state == FB_SLEEP ? FB_AWAKE : FB_SLEEP; ret = wait_for_file(fb_file_names[next_state]); if (ret) continue; pthread_mutex_lock(&fb_state_mutex); fb_state = next_state; pthread_cond_signal(&fb_state_cond); pthread_mutex_unlock(&fb_state_mutex); } wait_for_fb = 0; return NULL; } /* Returns 1 if fb monitor thread started, 0 otherwise */ static int start_fb_monitor_thread(void) { if (access(fb_file_names[FB_SLEEP], F_OK)) return 0; if (access(fb_file_names[FB_AWAKE], F_OK)) return 0; return !pthread_create(&fb_monitor_thread, NULL, fb_monitor_thread_func, NULL); } static int earlysuspend_enter(void) { int ret; int len = ARRAY_SIZE(mem_str) - 1; ret = sysfs_write(state_path, mem_str, len); if (ret == len && wait_for_fb) { pthread_mutex_lock(&fb_state_mutex); while (fb_state != FB_SLEEP) pthread_cond_wait(&fb_state_cond, &fb_state_mutex); pthread_mutex_unlock(&fb_state_mutex); } return ret < 0 ? ret : 0; } static int earlysuspend_exit(void) { int ret; int len = ARRAY_SIZE(on_str) - 1; ret = sysfs_write(state_path, on_str, len); if (ret == len && wait_for_fb) { pthread_mutex_lock(&fb_state_mutex); while (fb_state != FB_AWAKE) pthread_cond_wait(&fb_state_cond, &fb_state_mutex); pthread_mutex_unlock(&fb_state_mutex); } return ret < 0 ? ret : 0; } static int earlysuspend_acquire_wake_lock(const char *name) { int ret = sysfs_write(wakelock_path, name, strlen(name)); return ret < 0 ? ret : 0; } static int earlysuspend_release_wake_lock(const char *name) { int ret = sysfs_write(wakeunlock_path, name, strlen(name)); return ret < 0 ? ret : 0; } static const struct suspend_handler earlysuspend_handler = { .name = earlysuspend_name, .enter = earlysuspend_enter, .exit = earlysuspend_exit, .acquire_wake_lock = earlysuspend_acquire_wake_lock, .release_wake_lock = earlysuspend_release_wake_lock, }; const struct suspend_handler *earlysuspend_detect(void) { int len, ret; if (sysfs_file_exists(wakelock_path) && sysfs_file_exists(state_path)) { len = ARRAY_SIZE(on_str) - 1; ret = sysfs_write(state_path, on_str, len); if (ret != len) { return NULL; } wait_for_fb = start_fb_monitor_thread(); return &earlysuspend_handler; } return NULL; } repowerd-2023.07/src/adapters/libsuspend/legacy.c000066400000000000000000000043711446034100200216670ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "common.h" #include "sysfs.h" static const char legacy_name[] = "legacy"; static const char state_path[] = "/sys/power/state"; static const char wakelock_path[] = "/sys/power/wake_lock"; static const char wakeup_count_path[] = "/sys/power/wakeup_count"; static const char mem_str[] = "mem"; #define WAKEUP_COUNT_LEN 64 static int wakeup_count_supported, wakeup_count_valid; static char wakeup_count[WAKEUP_COUNT_LEN]; static int legacy_prepare(void) { int ret; if (wakeup_count_supported) { ret = sysfs_read(wakeup_count_path, wakeup_count, WAKEUP_COUNT_LEN); if (ret < 0) { wakeup_count_valid = 0; return ret; } wakeup_count_valid = 1; } return 0; } static int legacy_enter(void) { int ret; if (wakeup_count_supported && wakeup_count_valid) { wakeup_count_valid = 0; ret = sysfs_write(wakeup_count_path, wakeup_count, strlen(wakeup_count)); if (ret < 0) { /* Wakup happened since reading wakeup_count */ return ret; } } ret = sysfs_write(state_path, mem_str, ARRAY_SIZE(mem_str) - 1); return ret < 0 ? ret : 0; } static const struct suspend_handler legacy_handler = { .name = legacy_name, .prepare = legacy_prepare, .enter = legacy_enter, }; const struct suspend_handler *legacy_detect(void) { if (sysfs_file_exists(state_path) && !sysfs_file_exists(wakelock_path)) { wakeup_count_supported = sysfs_file_exists(wakeup_count_path); return &legacy_handler; } return NULL; } repowerd-2023.07/src/adapters/libsuspend/libsuspend.c000066400000000000000000000040751446034100200225740ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "libsuspend.h" #include "common.h" const struct suspend_handler *handler; void libsuspend_init(int force_mock) { if (!force_mock) { handler = earlysuspend_detect(); if (handler) return; handler = autosleep_detect(); if (handler) return; handler = legacy_detect(); if (handler) return; } handler = mocksuspend_detect(); } const char *libsuspend_getname(void) { if (!handler) return "not-initialized yet"; return handler->name; } int libsuspend_prepare_suspend(void) { if (!handler) return -ENODEV; if (handler->prepare) return handler->prepare(); return 0; } int libsuspend_enter_suspend(void) { if (!handler) return -ENODEV; if (handler->enter) return handler->enter(); return 0; } int libsuspend_exit_suspend(void) { if (!handler) return -ENODEV; if (handler->exit) return handler->exit(); return 0; } int libsuspend_acquire_wake_lock(const char *name) { if (!handler) return -ENODEV; if (handler->acquire_wake_lock) return handler->acquire_wake_lock(name); return 0; } int libsuspend_release_wake_lock(const char *name) { if (!handler) return -ENODEV; if (handler->release_wake_lock) return handler->release_wake_lock(name); return 0; } repowerd-2023.07/src/adapters/libsuspend/libsuspend.h000066400000000000000000000020651446034100200225760ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LIBSUSPEND_H #define LIBSUSPEND_H #ifdef __cplusplus extern "C" { #endif void libsuspend_init(int force_mock); const char *libsuspend_getname(void); int libsuspend_prepare_suspend(void); int libsuspend_enter_suspend(void); int libsuspend_exit_suspend(void); int libsuspend_acquire_wake_lock(const char *name); int libsuspend_release_wake_lock(const char *name); #ifdef __cplusplus } #endif #endif /* LIBSUSPEND_H */ repowerd-2023.07/src/adapters/libsuspend/mocksuspend.c000066400000000000000000000027231446034100200227550ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "common.h" static const char mocksuspend_name[] = "mocksuspend"; static int mocksuspend_prepare(void) { return 0; } static int mocksuspend_enter(void) { return 0; } static int mocksuspend_exit(void) { return 0; } static int mocksuspend_acquire_wake_lock(const char *name) { (void)name; return 0; } static int mocksuspend_release_wake_lock(const char *name) { (void)name; return 0; } static const struct suspend_handler mocksuspend_handler = { .name = mocksuspend_name, .prepare = mocksuspend_prepare, .enter = mocksuspend_enter, .exit = mocksuspend_exit, .acquire_wake_lock = mocksuspend_acquire_wake_lock, .release_wake_lock = mocksuspend_release_wake_lock, }; const struct suspend_handler *mocksuspend_detect(void) { return &mocksuspend_handler; } repowerd-2023.07/src/adapters/libsuspend/sysfs.c000066400000000000000000000025251446034100200215710ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include int sysfs_file_exists(const char *path) { return !access(path, F_OK); } int sysfs_read(const char *path, void *buf, int len) { int fd; ssize_t ret; fd = open(path, O_RDONLY); if (fd == -1) return -errno; ret = read(fd, buf, len); if (ret == -1) ret = -errno; close(fd); return ret; } int sysfs_write(const char *path, const void *buf, int len) { int fd; ssize_t ret; fd = open(path, O_WRONLY); if (fd == -1) return -errno; ret = write(fd, buf, len); if (ret == -1) ret = -errno; close(fd); return ret; } repowerd-2023.07/src/adapters/libsuspend/sysfs.h000066400000000000000000000015341446034100200215750ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This file is part of powerd. * * powerd is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * powerd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SYSFS_H #define SYSFS_H int sysfs_file_exists(const char *path); int sysfs_read(const char *path, void *buf, int len); int sysfs_write(const char *path, const void *buf, int len); #endif /* SYSFS_H */ repowerd-2023.07/src/adapters/libsuspend_system_power_control.cpp000066400000000000000000000061371446034100200253450ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "libsuspend_system_power_control.h" #include "libsuspend/libsuspend.h" #include "src/core/log.h" #include namespace { char const* const log_tag = "LibsuspendSystemPowerControl"; } repowerd::LibsuspendSystemPowerControl::LibsuspendSystemPowerControl( std::shared_ptr const& log) : log{log} { libsuspend_init(0); if (std::string{libsuspend_getname()} == "mocksuspend") throw std::runtime_error{"Failed to initialize libsuspend"}; log->logDebug(log_tag, "Initialized using backend %s", libsuspend_getname()); } void repowerd::LibsuspendSystemPowerControl::start_processing() { } repowerd::HandlerRegistration repowerd::LibsuspendSystemPowerControl::register_system_resume_handler( SystemResumeHandler const&) { return HandlerRegistration{}; } repowerd::HandlerRegistration repowerd::LibsuspendSystemPowerControl::register_system_allow_suspend_handler( SystemAllowSuspendHandler const&) { return HandlerRegistration{}; } repowerd::HandlerRegistration repowerd::LibsuspendSystemPowerControl::register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const&) { return HandlerRegistration{}; } void repowerd::LibsuspendSystemPowerControl::allow_automatic_suspend( std::string const& id) { std::lock_guard lock{suspend_mutex}; log->logDebug(log_tag, "allow_suspend(%s)", id.c_str()); if (suspend_disallowances.erase(id) > 0 && suspend_disallowances.empty()) { log->logDebug(log_tag, "Preparing for suspend"); libsuspend_prepare_suspend(); libsuspend_enter_suspend(); } } void repowerd::LibsuspendSystemPowerControl::disallow_automatic_suspend( std::string const& id) { std::lock_guard lock{suspend_mutex}; log->logDebug(log_tag, "disallow_suspend(%s)", id.c_str()); auto const could_be_suspended = suspend_disallowances.empty(); suspend_disallowances.insert(id); if (could_be_suspended) { log->logDebug(log_tag, "exiting suspend"); libsuspend_exit_suspend(); } } void repowerd::LibsuspendSystemPowerControl::power_off() { log->logDebug(log_tag, "power_off()"); if (system("shutdown -P now")) {} } void repowerd::LibsuspendSystemPowerControl::suspend() { } void repowerd::LibsuspendSystemPowerControl::allow_default_system_handlers() { } void repowerd::LibsuspendSystemPowerControl::disallow_default_system_handlers() { } repowerd-2023.07/src/adapters/libsuspend_system_power_control.h000066400000000000000000000035551446034100200250130ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/system_power_control.h" #include #include #include namespace repowerd { class Log; class LibsuspendSystemPowerControl : public SystemPowerControl { public: LibsuspendSystemPowerControl(std::shared_ptr const& log); void start_processing() override; HandlerRegistration register_system_resume_handler( SystemResumeHandler const& system_resume_handler) override; HandlerRegistration register_system_allow_suspend_handler( SystemAllowSuspendHandler const& system_allow_suspend_handler) override; HandlerRegistration register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const& system_disallow_suspend_handler) override; void allow_automatic_suspend(std::string const& id) override; void disallow_automatic_suspend(std::string const& id) override; void power_off() override; void suspend() override; void allow_default_system_handlers() override; void disallow_default_system_handlers() override; private: std::shared_ptr const log; std::mutex suspend_mutex; std::unordered_set suspend_disallowances; }; } repowerd-2023.07/src/adapters/light_sensor.h000066400000000000000000000023621446034100200207560ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/handler_registration.h" #include namespace repowerd { using LightHandler = std::function; class LightSensor { public: virtual ~LightSensor() = default; virtual HandlerRegistration register_light_handler( LightHandler const& handler) = 0; virtual void enable_light_events() = 0; virtual void disable_light_events() = 0; protected: LightSensor() = default; LightSensor (LightSensor const&) = default; LightSensor& operator=(LightSensor const&) = default; }; } repowerd-2023.07/src/adapters/logind_session_tracker.cpp000066400000000000000000000351431446034100200233460ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "logind_session_tracker.h" #include "android_device_quirks.h" #include "event_loop_handler_registration.h" #include "scoped_g_error.h" #include "src/core/log.h" #include namespace { char const* const log_tag = "LogindSessionTracker"; auto null_arg1_handler = [](auto){}; auto null_arg2_handler = [](auto,auto){}; char const* const dbus_logind_name = "org.freedesktop.login1"; char const* const dbus_manager_path = "/org/freedesktop/login1"; char const* const dbus_manager_interface = "org.freedesktop.login1.Manager"; char const* const dbus_seat_path = "/org/freedesktop/login1/seat/seat0"; char const* const dbus_seat_interface = "org.freedesktop.login1.Seat"; char const* const dbus_session_interface = "org.freedesktop.login1.Session"; repowerd::SessionType logind_session_type_to_repowerd_type( std::string const& logind_session_type) { if (logind_session_type == "mir" || logind_session_type == "wayland") return repowerd::SessionType::RepowerdCompatible; else return repowerd::SessionType::RepowerdIncompatible; } uid_t euid_of_pid(repowerd::Filesystem& fs, pid_t pid) { auto proc_status = fs.istream("/proc/" + std::to_string(pid) + "/status"); uid_t euid = -1; std::string line; while (std::getline(*proc_status, line)) { if (line.find("Uid") == 0) { char const* const any_number = "0123456789"; char const* const any_whitespace = "\t "; auto const ruid_pos = line.find_first_of(any_number); auto const space_pos = line.find_first_of(any_whitespace, ruid_pos); auto euid_pos = line.find_first_of(any_number, space_pos); euid = std::stoi(line.substr(euid_pos)); break; } } return euid; } } repowerd::LogindSessionTracker::LogindSessionTracker( std::shared_ptr const& filesystem, std::shared_ptr const& log, DeviceQuirks const& quirks, std::string const& dbus_bus_address) : filesystem{filesystem}, log{log}, ignore_session_deactivation{quirks.ignore_session_deactivation()}, dbus_connection{dbus_bus_address}, dbus_event_loop{"Logind"}, active_session_changed_handler{null_arg2_handler}, session_removed_handler{null_arg1_handler}, active_session_id{invalid_session_id} { } void repowerd::LogindSessionTracker::start_processing() { dbus_seat_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_logind_name, "org.freedesktop.DBus.Properties", "PropertiesChanged", dbus_seat_path, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); dbus_manager_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_logind_name, dbus_manager_interface, "SessionRemoved", dbus_manager_path, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); dbus_event_loop.enqueue([this] { set_initial_active_session(); }).get(); } repowerd::HandlerRegistration repowerd::LogindSessionTracker::register_active_session_changed_handler( ActiveSessionChangedHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->active_session_changed_handler = handler; }, [this] { this->active_session_changed_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::LogindSessionTracker::register_session_removed_handler( SessionRemovedHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->session_removed_handler = handler; }, [this] { this->session_removed_handler = null_arg1_handler; }}; } std::string repowerd::LogindSessionTracker::session_for_pid(pid_t pid) { std::string ret_session_id{invalid_session_id}; dbus_event_loop.enqueue( [&] { auto const session_path = dbus_get_session_path_by_pid(pid); ret_session_id = session_id_for_path(session_path); if (ret_session_id == invalid_session_id) { auto const& active_session_path = tracked_sessions[active_session_id].path; auto const active_session_uid = dbus_get_session_uid(active_session_path); auto const pid_euid = euid_of_pid(*filesystem, pid); if (pid_euid == 0 || pid_euid == active_session_uid) ret_session_id = active_session_id; } }).get(); return ret_session_id; } void repowerd::LogindSessionTracker::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* object_path_cstr, gchar const* /*interface_name*/, gchar const* signal_name_cstr, GVariant* parameters) { std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; std::string const object_path{object_path_cstr ? object_path_cstr : ""}; if (signal_name == "PropertiesChanged") { char const* properties_interface_cstr{""}; GVariantIter* properties_iter; g_variant_get(parameters, "(&sa{sv}as)", &properties_interface_cstr, &properties_iter, nullptr); std::string const properties_interface{properties_interface_cstr}; if (properties_interface == "org.freedesktop.login1.Seat") handle_dbus_change_seat_properties(object_path, properties_iter); g_variant_iter_free(properties_iter); } else if (signal_name == "SessionRemoved") { char const* session_id_cstr{""}; g_variant_get(parameters, "(&s&o)", &session_id_cstr, nullptr); remove_session(session_id_cstr); } } void repowerd::LogindSessionTracker::handle_dbus_change_seat_properties( std::string const& seat, GVariantIter* properties_iter) { char const* key_cstr{""}; GVariant* value{nullptr}; while (g_variant_iter_next(properties_iter, "{&sv}", &key_cstr, &value)) { auto const key_str = std::string{key_cstr}; if (key_str == "ActiveSession") { char const* session_id_cstr{""}; char const* session_path_cstr{""}; g_variant_get(value, "(&s&o)", &session_id_cstr, &session_path_cstr); log->logDebug(log_tag, "change_seat_properties(%s), ActiveSession=(%s,%s)", seat.c_str(), session_id_cstr, session_path_cstr); if (std::string{session_id_cstr}.empty()) deactivate_session(); else activate_session(session_id_cstr, session_path_cstr); } g_variant_unref(value); } } void repowerd::LogindSessionTracker::set_initial_active_session() { auto const active_session = dbus_get_active_session(); if (!active_session.first.empty()) activate_session(active_session.first, active_session.second); } void repowerd::LogindSessionTracker::track_session( std::string const& session_id, std::string const& session_path) { auto const session_type = dbus_get_session_type(session_path); log->logDebug(log_tag, "track_session(%s), type=%s", session_id.c_str(), session_type.c_str()); tracked_sessions[session_id] = { session_path, logind_session_type_to_repowerd_type(session_type) }; } void repowerd::LogindSessionTracker::remove_session(std::string const& session_id) { auto const iter = tracked_sessions.find(session_id); if (iter != tracked_sessions.end()) { log->logDebug(log_tag, "remove_session(%s)", session_id.c_str()); tracked_sessions.erase(iter); session_removed_handler(session_id); } } void repowerd::LogindSessionTracker::activate_session( std::string const& session_id, std::string const& session_path) { auto iter = tracked_sessions.find(session_id); if (iter == tracked_sessions.end()) { track_session(session_id, session_path); iter = tracked_sessions.find(session_id); } if (iter != tracked_sessions.end() && iter->first != active_session_id) { log->logDebug(log_tag, "activate_session(%s)", session_id.c_str()); active_session_id = iter->first; active_session_changed_handler(iter->first, iter->second.type); } } void repowerd::LogindSessionTracker::deactivate_session() { log->logDebug(log_tag, "deactivate_session()"); if (ignore_session_deactivation) return; active_session_id = invalid_session_id; active_session_changed_handler( repowerd::invalid_session_id, repowerd::SessionType::RepowerdIncompatible); } std::pair repowerd::LogindSessionTracker::dbus_get_active_session() { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, dbus_seat_path, "org.freedesktop.DBus.Properties", "Get", g_variant_new("(ss)", dbus_seat_interface, "ActiveSession"), G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_get_active_session() failed to get ActiveSession: %s", error.message_str().c_str()); return {"",""}; } GVariant* active_session_variant{nullptr}; g_variant_get(result, "(v)", &active_session_variant); char const* session_id_cstr{""}; char const* session_path_cstr{""}; g_variant_get(active_session_variant, "(&s&o)", &session_id_cstr, &session_path_cstr); std::string const session_id{session_id_cstr}; std::string const session_path{session_path_cstr}; g_variant_unref(active_session_variant); g_variant_unref(result); return {session_id, session_path}; } std::string repowerd::LogindSessionTracker::dbus_get_session_type(std::string const& session_path) { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, session_path.c_str(), "org.freedesktop.DBus.Properties", "Get", g_variant_new("(ss)", dbus_session_interface, "Type"), G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_get_session_type() failed to get session Type: %s", error.message_str().c_str()); return ""; } GVariant* type_variant{nullptr}; g_variant_get(result, "(v)", &type_variant); char const* session_type_cstr{""}; g_variant_get(type_variant, "&s", &session_type_cstr); std::string const session_type{session_type_cstr}; g_variant_unref(type_variant); g_variant_unref(result); return session_type; } std::string repowerd::LogindSessionTracker::dbus_get_session_path_by_pid(pid_t pid) { int constexpr timeout_default = 1000; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, dbus_manager_path, dbus_manager_interface, "GetSessionByPID", g_variant_new("(u)", pid), G_VARIANT_TYPE("(o)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_get_session_by_pid() failed: %s", error.message_str().c_str()); return invalid_session_id; } char const* session_path_cstr{""}; g_variant_get(result, "(&o)", &session_path_cstr); std::string const session_path{session_path_cstr}; g_variant_unref(result); return session_path; } std::string repowerd::LogindSessionTracker::session_id_for_path( std::string const& session_path) { if (session_path.empty()) return invalid_session_id; auto const iter = std::find_if( tracked_sessions.begin(), tracked_sessions.end(), [&session_path] (auto const& kv) { return kv.second.path == session_path; }); return iter != tracked_sessions.end() ? iter->first : invalid_session_id; } uid_t repowerd::LogindSessionTracker::dbus_get_session_uid(std::string const& session_path) { int constexpr timeout_three_sec = 3000; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, session_path.c_str(), "org.freedesktop.DBus.Properties", "Get", g_variant_new("(ss)", dbus_session_interface, "User"), G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, timeout_three_sec, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_get_session_uid() failed to get session uid: %s", error.message_str().c_str()); return -1; } GVariant* type_variant{nullptr}; g_variant_get(result, "(v)", &type_variant); guint uid = -1; g_variant_get(type_variant, "(u&o)", &uid, nullptr); g_variant_unref(type_variant); g_variant_unref(result); return uid; } repowerd-2023.07/src/adapters/logind_session_tracker.h000066400000000000000000000062251446034100200230120ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/session_tracker.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include "filesystem.h" #include #include #include namespace repowerd { class Log; class DeviceQuirks; class LogindSessionTracker : public SessionTracker { public: LogindSessionTracker( std::shared_ptr const& filesystem, std::shared_ptr const& log, DeviceQuirks const& device_quirks, std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_active_session_changed_handler( ActiveSessionChangedHandler const& handler) override; HandlerRegistration register_session_removed_handler( SessionRemovedHandler const& handler) override; std::string session_for_pid(pid_t pid) override; private: void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); void handle_dbus_change_seat_properties( std::string const& seat, GVariantIter* properties_iter); void set_initial_active_session(); void track_session(std::string const& session_id, std::string const& session_path); void remove_session(std::string const& session_path); void activate_session(std::string const& session_id, std::string const& session_path); void deactivate_session(); std::pair dbus_get_active_session(); std::string dbus_get_session_type(std::string const& session_path); std::string dbus_get_session_path_by_pid(pid_t pid); std::string session_id_for_path(std::string const& session_path); uid_t dbus_get_session_uid(std::string const& session_path); std::shared_ptr const filesystem; std::shared_ptr const log; bool const ignore_session_deactivation; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration dbus_seat_signal_handler_registration; HandlerRegistration dbus_manager_signal_handler_registration; ActiveSessionChangedHandler active_session_changed_handler; SessionRemovedHandler session_removed_handler; struct SessionInfo { std::string path; SessionType type; }; std::unordered_map tracked_sessions; std::string active_session_id; }; } repowerd-2023.07/src/adapters/logind_system_power_control.cpp000066400000000000000000000267421446034100200244550ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "logind_system_power_control.h" #include "scoped_g_error.h" #include "event_loop_handler_registration.h" #include "src/core/log.h" #include #include namespace { char const* const log_tag = "LogindSystemPowerControl"; char const* const dbus_logind_name = "org.freedesktop.login1"; char const* const dbus_manager_path = "/org/freedesktop/login1"; char const* const dbus_manager_interface = "org.freedesktop.login1.Manager"; char const* const suspend_id = "LogindSystemPowerControl"; auto null_arg_handler = []{}; auto null_arg1_handler = [](auto){}; } repowerd::LogindSystemPowerControl::LogindSystemPowerControl( std::shared_ptr const& log, std::string const& dbus_bus_address) : log{log}, dbus_connection{dbus_bus_address}, dbus_event_loop{"SystemPower"}, system_resume_handler{null_arg_handler}, system_allow_suspend_handler{null_arg1_handler}, system_disallow_suspend_handler{null_arg1_handler}, is_suspend_blocked{false}, idle_and_lid_inhibition_fd{-1} { } void repowerd::LogindSystemPowerControl::start_processing() { auto const dbus_signal_handler = [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }; dbus_manager_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_logind_name, dbus_manager_interface, "PrepareForSleep", dbus_manager_path, dbus_signal_handler); dbus_manager_properties_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_logind_name, "org.freedesktop.DBus.Properties", "PropertiesChanged", dbus_manager_path, dbus_signal_handler); dbus_event_loop.enqueue([this] { initialize_is_suspend_blocked(); }).get(); } repowerd::HandlerRegistration repowerd::LogindSystemPowerControl::register_system_resume_handler( SystemResumeHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->system_resume_handler = handler; }, [this] { this->system_resume_handler = null_arg_handler; }}; } repowerd::HandlerRegistration repowerd::LogindSystemPowerControl::register_system_allow_suspend_handler( SystemAllowSuspendHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->system_allow_suspend_handler = handler; }, [this] { this->system_allow_suspend_handler = null_arg1_handler; }}; } repowerd::HandlerRegistration repowerd::LogindSystemPowerControl::register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->system_disallow_suspend_handler = handler; }, [this] { this->system_disallow_suspend_handler = null_arg1_handler; }}; } void repowerd::LogindSystemPowerControl::allow_automatic_suspend(std::string const&) { } void repowerd::LogindSystemPowerControl::disallow_automatic_suspend(std::string const&) { } void repowerd::LogindSystemPowerControl::power_off() { dbus_power_off(); } void repowerd::LogindSystemPowerControl::suspend() { dbus_suspend(); } void repowerd::LogindSystemPowerControl::allow_default_system_handlers() { std::lock_guard lock{inhibitions_mutex}; log->logDebug(log_tag, "releasing idle and lid inhibition"); idle_and_lid_inhibition_fd = Fd{-1}; } void repowerd::LogindSystemPowerControl::disallow_default_system_handlers() { auto inhibition_fd = dbus_inhibit("idle:handle-lid-switch", "repowerd handles idle and lid"); std::lock_guard lock{inhibitions_mutex}; idle_and_lid_inhibition_fd = std::move(inhibition_fd); } void repowerd::LogindSystemPowerControl::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* signal_name_cstr, GVariant* parameters) { std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; if (signal_name == "PrepareForSleep") { gboolean start{FALSE}; g_variant_get(parameters, "(b)", &start); log->logDebug(log_tag, "dbus_PrepareForSleep(%s)", start ? "true" : "false"); if (start == FALSE) system_resume_handler(); } else if (signal_name == "PropertiesChanged") { char const* properties_interface_cstr{""}; GVariantIter* properties_iter; g_variant_get(parameters, "(&sa{sv}as)", &properties_interface_cstr, &properties_iter, nullptr); std::string const properties_interface{properties_interface_cstr}; if (properties_interface == "org.freedesktop.login1.Manager") handle_dbus_change_manager_properties(properties_iter); g_variant_iter_free(properties_iter); } } void repowerd::LogindSystemPowerControl::handle_dbus_change_manager_properties( GVariantIter* properties_iter) { char const* key_cstr{""}; GVariant* value{nullptr}; while (g_variant_iter_next(properties_iter, "{&sv}", &key_cstr, &value)) { auto const key_str = std::string{key_cstr}; if (key_str == "BlockInhibited") { // TODO: logind incorrectly returns the previous property value, // so we need to get it manually auto const blocks = dbus_get_block_inhibited(); log->logDebug(log_tag, "change_manager_properties(), BlockInhibited=%s", blocks.c_str()); auto const prev_is_suspend_blocked = is_suspend_blocked; update_suspend_block(blocks); if (is_suspend_blocked != prev_is_suspend_blocked) notify_suspend_block_state(); } g_variant_unref(value); } } repowerd::Fd repowerd::LogindSystemPowerControl::dbus_inhibit( char const* what, char const* why) { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; GUnixFDList *fd_list = nullptr; ScopedGError error; char const* const who = "repowerd"; char const* const mode = "block"; log->logDebug(log_tag, "dbus_inhibit(%s,%s)...", what, why); auto const result = g_dbus_connection_call_with_unix_fd_list_sync( dbus_connection, dbus_logind_name, dbus_manager_path, dbus_manager_interface, "Inhibit", g_variant_new("(ssss)", what, who, why, mode), G_VARIANT_TYPE("(h)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, nullptr, &fd_list, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_inhibit() failed: %s", error.message_str().c_str()); return Fd{-1}; } gint32 inhibit_fd_index = -1; g_variant_get(result, "(h)", &inhibit_fd_index); g_variant_unref(result); auto inhibit_fd = Fd{g_unix_fd_list_get(fd_list, inhibit_fd_index, error)}; if (inhibit_fd < 0) log->logWarning(log_tag, "dbus_inhibit() get fd failed: %s", error.message_str().c_str()); else log->logDebug(log_tag, "dbus_inhibit(%s,%s) done", what, why); g_object_unref(fd_list); return inhibit_fd; } void repowerd::LogindSystemPowerControl::dbus_power_off() { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; log->logDebug(log_tag, "dbus_power_off()..."); auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, dbus_manager_path, dbus_manager_interface, "PowerOff", g_variant_new("(b)", FALSE), nullptr, G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) log->logWarning(log_tag, "dbus_power_off() failed: %s", error.message_str().c_str()); else log->logDebug(log_tag, "dbus_power_off() done"); g_variant_unref(result); } void repowerd::LogindSystemPowerControl::dbus_suspend() { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; log->logDebug(log_tag, "dbus_suspend()..."); auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, dbus_manager_path, dbus_manager_interface, "Suspend", g_variant_new("(b)", FALSE), nullptr, G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) log->logWarning(log_tag, "dbus_suspend() failed: %s", error.message_str().c_str()); else log->logDebug(log_tag, "dbus_suspend() done"); g_variant_unref(result); } void repowerd::LogindSystemPowerControl::initialize_is_suspend_blocked() { auto const blocks = dbus_get_block_inhibited(); log->logDebug(log_tag, "initialize_is_suspend_blocked(), BlockInhibited=%s", blocks.c_str()); update_suspend_block(blocks); notify_suspend_block_state(); } std::string repowerd::LogindSystemPowerControl::dbus_get_block_inhibited() { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_logind_name, dbus_manager_path, "org.freedesktop.DBus.Properties", "Get", g_variant_new("(ss)", dbus_manager_interface, "BlockInhibited"), G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_get_block_inhibited() failed to get BlockInhibited: %s", error.message_str().c_str()); return ""; } GVariant* block_inhibited_variant{nullptr}; g_variant_get(result, "(v)", &block_inhibited_variant); char const* blocks_cstr{""}; g_variant_get(block_inhibited_variant, "&s", &blocks_cstr); std::string const blocks{blocks_cstr}; g_variant_unref(block_inhibited_variant); g_variant_unref(result); return blocks; } void repowerd::LogindSystemPowerControl::update_suspend_block(std::string const& blocks) { is_suspend_blocked = blocks.find("sleep") != std::string::npos; } void repowerd::LogindSystemPowerControl::notify_suspend_block_state() { if (is_suspend_blocked) system_disallow_suspend_handler(suspend_id); else system_allow_suspend_handler(suspend_id); } repowerd-2023.07/src/adapters/logind_system_power_control.h000066400000000000000000000057231446034100200241160ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/system_power_control.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include "fd.h" #include #include #include namespace repowerd { class Log; class LogindSystemPowerControl : public SystemPowerControl { public: LogindSystemPowerControl( std::shared_ptr const& log, std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_system_resume_handler( SystemResumeHandler const& system_resume_handler) override; HandlerRegistration register_system_allow_suspend_handler( SystemAllowSuspendHandler const& system_allow_suspend_handler) override; HandlerRegistration register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const& system_disallow_suspend_handler) override; void allow_automatic_suspend(std::string const& id) override; void disallow_automatic_suspend(std::string const& id) override; void power_off() override; void suspend() override; void allow_default_system_handlers() override; void disallow_default_system_handlers() override; private: void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); void handle_dbus_change_manager_properties(GVariantIter* properties_iter); Fd dbus_inhibit(char const* what, char const* who); void dbus_power_off(); void dbus_suspend(); void initialize_is_suspend_blocked(); std::string dbus_get_block_inhibited(); void update_suspend_block(std::string const& blocks); void notify_suspend_block_state(); std::shared_ptr const log; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration dbus_manager_signal_handler_registration; HandlerRegistration dbus_manager_properties_handler_registration; SystemResumeHandler system_resume_handler; SystemAllowSuspendHandler system_allow_suspend_handler; SystemDisallowSuspendHandler system_disallow_suspend_handler; bool is_suspend_blocked; std::mutex inhibitions_mutex; Fd idle_and_lid_inhibition_fd; }; } repowerd-2023.07/src/adapters/lsc_display.cpp000066400000000000000000000146641446034100200211270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "lsc_display.h" #include "scoped_g_error.h" #include namespace { char const* const lsc_display_bus_name = "com.lomiri.SystemCompositor.Display"; char const* const lsc_display_object_path = "/com/lomiri/SystemCompositor/Display"; char const* const lsc_display_interface_name = "com.lomiri.SystemCompositor.Display"; char const* const log_tag = "LscDisplay"; std::string filter_to_str(repowerd::DisplayPowerControlFilter filter) { std::string filter_str; if (filter == repowerd::DisplayPowerControlFilter::all) filter_str = "all"; else if (filter == repowerd::DisplayPowerControlFilter::internal) filter_str = "internal"; else if (filter == repowerd::DisplayPowerControlFilter::external) filter_str = "external"; else filter_str = "(unknown)"; return filter_str; } } repowerd::LscDisplay::LscDisplay( std::shared_ptr const& log, std::string const& dbus_bus_address) : log{log}, dbus_connection{dbus_bus_address}, dbus_event_loop{"Display"}, has_active_external_displays_{false} { dbus_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, lsc_display_bus_name, "org.freedesktop.DBus.Properties", "PropertiesChanged", lsc_display_object_path, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); dbus_event_loop.enqueue([this] { dbus_query_active_outputs(); }).get(); } void repowerd::LscDisplay::turn_on(DisplayPowerControlFilter filter) { auto const filter_str = filter_to_str(filter); log->logDebug(log_tag, "turn_on(%s)", filter_str.c_str()); auto const reply = g_dbus_connection_call_sync( dbus_connection, lsc_display_bus_name, lsc_display_object_path, lsc_display_interface_name, "TurnOn", g_variant_new("(s)", filter_str.c_str()), nullptr, G_DBUS_CALL_FLAGS_NONE, /* timeout_msec */ 1000, nullptr, nullptr); if (reply) g_variant_unref(reply); } void repowerd::LscDisplay::turn_off(DisplayPowerControlFilter filter) { auto const filter_str = filter_to_str(filter); log->logDebug(log_tag, "turn_off(%s)", filter_str.c_str()); g_dbus_connection_call( dbus_connection, lsc_display_bus_name, lsc_display_object_path, lsc_display_interface_name, "TurnOff", g_variant_new("(s)", filter_str.c_str()), nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr); } bool repowerd::LscDisplay::has_active_external_displays() { return has_active_external_displays_; } void repowerd::LscDisplay::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* signal_name_cstr, GVariant* parameters) { std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; if (signal_name == "PropertiesChanged") { char const* properties_interface_cstr{""}; GVariantIter* properties_iter{nullptr}; g_variant_get(parameters, "(&sa{sv}as)", &properties_interface_cstr, &properties_iter, nullptr); std::string const properties_interface{properties_interface_cstr}; if (properties_interface == lsc_display_interface_name) dbus_PropertiesChanged(properties_iter); g_variant_iter_free(properties_iter); } } void repowerd::LscDisplay::dbus_PropertiesChanged( GVariantIter* properties_iter) { char const* key_cstr{""}; GVariant* value{nullptr}; while (g_variant_iter_next(properties_iter, "{&sv}", &key_cstr, &value)) { auto const key_str = std::string{key_cstr ? key_cstr : ""}; if (key_str == "ActiveOutputs") { gint32 internal{0}; gint32 external{0}; g_variant_get(value, "(ii)", &internal, &external); dbus_ActiveOutputs(internal, external); } g_variant_unref(value); } } void repowerd::LscDisplay::dbus_ActiveOutputs( int32_t internal, int32_t external) { log->logDebug(log_tag, "dbus_ActiveOutputs(internal=%d, external=%d)", internal, external); has_active_external_displays_ = (external > 0); } void repowerd::LscDisplay::dbus_query_active_outputs() { log->logDebug(log_tag, "dbus_query_active_outputs()"); int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, lsc_display_bus_name, lsc_display_object_path, "org.freedesktop.DBus.Properties", "Get", g_variant_new("(ss)", lsc_display_interface_name, "ActiveOutputs"), G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "dbus_get_active_outputs() failed to get ActiveOutputs: %s", error.message_str().c_str()); return; } GVariant* property_variant{nullptr}; g_variant_get(result, "(v)", &property_variant); gint32 internal{0}; gint32 external{0}; g_variant_get(property_variant, "(ii)", &internal, &external); dbus_ActiveOutputs(internal, external); g_variant_unref(property_variant); g_variant_unref(result); } repowerd-2023.07/src/adapters/lsc_display.h000066400000000000000000000040321446034100200205600ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/display_power_control.h" #include "src/core/display_information.h" #include "src/core/handler_registration.h" #include "src/core/log.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include #include namespace repowerd { class Log; class LscDisplay : public DisplayPowerControl, public DisplayInformation { public: LscDisplay( std::shared_ptr const& log, std::string const& dbus_bus_address); // From DisplayPowerControl void turn_on(DisplayPowerControlFilter filter) override; void turn_off(DisplayPowerControlFilter filter) override; // From DisplayInformation bool has_active_external_displays() override; private: void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); void dbus_query_active_outputs(); void dbus_PropertiesChanged(GVariantIter* properties_iter); void dbus_ActiveOutputs(int32_t internal, int32_t external); std::shared_ptr const log; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration dbus_signal_handler_registration; std::atomic has_active_external_displays_; }; } repowerd-2023.07/src/adapters/lsc_power_button.cpp000066400000000000000000000061101446034100200221740ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "lsc_power_button.h" #include "event_loop_handler_registration.h" namespace { auto const null_handler = [](repowerd::PowerButtonState){}; char const* const dbus_power_button_name = "com.lomiri.SystemCompositor.PowerButton"; char const* const dbus_power_button_path = "/com/lomiri/SystemCompositor/PowerButton"; char const* const dbus_power_button_interface = "com.lomiri.SystemCompositor.PowerButton"; } repowerd::LscPowerButton::LscPowerButton( std::string const& dbus_bus_address) : dbus_connection{dbus_bus_address}, dbus_event_loop{"PowerButton"}, power_button_handler{null_handler} { } void repowerd::LscPowerButton::start_processing() { dbus_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_power_button_name, dbus_power_button_interface, nullptr, dbus_power_button_path, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); } repowerd::HandlerRegistration repowerd::LscPowerButton::register_power_button_handler( PowerButtonHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->power_button_handler = handler; }, [this] { this->power_button_handler = null_handler; }}; } void repowerd::LscPowerButton::notify_long_press() { g_dbus_connection_emit_signal( dbus_connection, nullptr, dbus_power_button_path, dbus_power_button_interface, "LongPress", nullptr, nullptr); } void repowerd::LscPowerButton::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* signal_name_cstr, GVariant* /*parameters*/) { std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; if (signal_name == "Press") power_button_handler(repowerd::PowerButtonState::pressed); else if (signal_name == "Release") power_button_handler(repowerd::PowerButtonState::released); } repowerd-2023.07/src/adapters/lsc_power_button.h000066400000000000000000000031531446034100200216450ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/power_button.h" #include "src/core/power_button_event_sink.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" namespace repowerd { class LscPowerButton : public PowerButton, public PowerButtonEventSink { public: LscPowerButton(std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_power_button_handler( PowerButtonHandler const& handler) override; void notify_long_press() override; private: void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration dbus_signal_handler_registration; PowerButtonHandler power_button_handler; }; } repowerd-2023.07/src/adapters/lsc_user_activity.cpp000066400000000000000000000061241446034100200223440ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "lsc_user_activity.h" #include "event_loop_handler_registration.h" namespace { auto const null_handler = [](repowerd::UserActivityType){}; char const* const dbus_user_activity_name = "com.lomiri.SystemCompositor.UserActivity"; char const* const dbus_user_activity_path = "/com/lomiri/SystemCompositor/UserActivity"; char const* const dbus_user_activity_interface = "com.lomiri.SystemCompositor.UserActivity"; repowerd::UserActivityType user_activity_type_from_dbus_value(int32_t value) { if (value == 0) return repowerd::UserActivityType::change_power_state; else return repowerd::UserActivityType::extend_power_state; } } repowerd::LscUserActivity::LscUserActivity( std::string const& dbus_bus_address) : dbus_connection{dbus_bus_address}, dbus_event_loop{"UserActivity"}, user_activity_handler{null_handler} { } void repowerd::LscUserActivity::start_processing() { dbus_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_user_activity_name, dbus_user_activity_interface, "Activity", dbus_user_activity_path, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); } repowerd::HandlerRegistration repowerd::LscUserActivity::register_user_activity_handler( UserActivityHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->user_activity_handler = handler; }, [this] { this->user_activity_handler = null_handler; }}; } void repowerd::LscUserActivity::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* signal_name_cstr, GVariant* parameters) { std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; if (signal_name == "Activity") { int32_t activity_type; g_variant_get(parameters, "(i)", &activity_type); user_activity_handler(user_activity_type_from_dbus_value(activity_type)); } } repowerd-2023.07/src/adapters/lsc_user_activity.h000066400000000000000000000027771446034100200220230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/user_activity.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" namespace repowerd { class LscUserActivity : public UserActivity { public: LscUserActivity(std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_user_activity_handler( UserActivityHandler const& handler) override; private: void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration dbus_signal_handler_registration; UserActivityHandler user_activity_handler; }; } repowerd-2023.07/src/adapters/monotone_spline.cpp000066400000000000000000000101171446034100200220160ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "monotone_spline.h" #include #include namespace { std::vector secant_slopes( std::vector const& points) { std::vector slopes; for (auto i = 0u; i < points.size() - 1; ++i) { auto dy = points[i+1].y - points[i].y; auto dx = points[i+1].x - points[i].x; slopes.push_back(dy/dx); } slopes.push_back(0); return slopes; } std::vector point_tangents(std::vector const& slopes) { std::vector tangents; tangents.push_back(slopes.front()); for (auto i = 1u; i < slopes.size() - 1; ++i) { if (slopes[i-1]*slopes[i] < 0) tangents.push_back(0); else tangents.push_back((slopes[i-1] + slopes[i]) / 2); } tangents.push_back(slopes[slopes.size() - 2]); return tangents; } void ensure_monotonicity(std::vector& tangents, std::vector const& slopes) { auto const alpha = [&](int i) { return tangents[i] / slopes[i]; }; auto const beta = [&](int i) { return (i < 0) ? 0 : tangents[i+1] / slopes[i]; }; for (auto i = 0u; i < slopes.size() - 1; ++i) { if (slopes[i] == 0.0) { tangents[i] = 0; tangents[++i] = 0; continue; } auto const alpha_i = alpha(i); if (alpha_i < 0 || beta(i-1) < 0) { tangents[i] = 0; continue; } if (alpha_i > 3) tangents[i] = 3 * slopes[i]; if (beta(i) > 3) tangents[i+1] = 3 * slopes[i]; } } std::vector calculate_monotone_point_tangents( std::vector const& points) { if (points.size() < 2) throw std::logic_error("Cannot create spline with fewer than two points"); auto const slopes = secant_slopes(points); auto tangents = point_tangents(slopes); ensure_monotonicity(tangents, slopes); return tangents; } std::vector sorted( std::vector const& points) { auto const cmp = [](auto const& p1, auto const& p2) { return p1.x < p2.x; }; auto sorted_points = points; std::sort(sorted_points.begin(), sorted_points.end(), cmp); return sorted_points; } } repowerd::MonotoneSpline::MonotoneSpline( std::vector const& points) : points{sorted(points)}, tangents{calculate_monotone_point_tangents(this->points)} { } double repowerd::MonotoneSpline::interpolate(double x) const { auto const i = find_index(x); if (i < 0) return points.front().y; if (i >= static_cast(points.size() - 1)) return points.back().y; auto const h = points[i+1].x - points[i].x; auto const t = (x - points[i].x) / h; auto const h00 = t * t * (2 * t - 3) + 1; auto const h10 = t * (1 + t * (t - 2)); auto const h01 = t * t * (3 - 2 * t); auto const h11 = t * t * (t - 1); return h00 * points[i].y + h10 * h * tangents[i] + h01 * points[i+1].y + h11 * h * tangents[i+1]; } int repowerd::MonotoneSpline::find_index(double x) const { if (x < points[0].x) return -1; for (auto i = 0u; i < points.size() - 1; ++i) { if (x >= points[i].x && x < points[i+1].x) return i; } return points.size() - 1; } repowerd-2023.07/src/adapters/monotone_spline.h000066400000000000000000000022231446034100200214620ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { // Implemented using Monotone cubic Hermite interpolation // See: https://en.wikipedia.org/wiki/Monotone_cubic_interpolation class MonotoneSpline { public: struct Point { double x; double y; }; MonotoneSpline(std::vector const& points); double interpolate(double x) const; private: int find_index(double x) const; std::vector points; std::vector tangents; }; } repowerd-2023.07/src/adapters/null_log.cpp000066400000000000000000000016221446034100200204220ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "null_log.h" repowerd::NullLog::NullLog(repowerd::LogLevel threshold) : repowerd::Log::Log(threshold) { } void repowerd::NullLog::logOutput(repowerd::LogLevel, char const*, char const*, va_list) { } repowerd-2023.07/src/adapters/null_log.h000066400000000000000000000016511446034100200200710ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/log.h" namespace repowerd { class NullLog : public Log { public: NullLog(LogLevel threshold); void logOutput(LogLevel level, char const* tag, char const* format, va_list ap) override; }; } repowerd-2023.07/src/adapters/ofono_voice_call_service.cpp000066400000000000000000000312671446034100200236370ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "ofono_voice_call_service.h" #include "event_loop_handler_registration.h" #include "src/core/log.h" #include namespace { char const* const log_tag = "OfonoVoiceCallService"; auto const null_handler = []{}; char const* const ofono_manager_interface = "org.ofono.Manager"; char const* const ofono_radio_settings_interface = "org.ofono.RadioSettings"; char const* const ofono_service_name = "org.ofono"; char const* const ofono_voice_call_manager_interface = "org.ofono.VoiceCallManager"; char const* const ofono_voice_call_interface = "org.ofono.VoiceCall"; repowerd::OfonoCallState ofono_call_state_from_string(std::string const& state_str) { repowerd::OfonoCallState state; if (state_str == "active") state = repowerd::OfonoCallState::active; else if (state_str == "alerting") state = repowerd::OfonoCallState::alerting; else if (state_str == "dialing") state = repowerd::OfonoCallState::dialing; else if (state_str == "disconnected") state = repowerd::OfonoCallState::disconnected; else if (state_str == "held") state = repowerd::OfonoCallState::held; else if (state_str == "incoming") state = repowerd::OfonoCallState::incoming; else if (state_str == "waiting") state = repowerd::OfonoCallState::waiting; else state = repowerd::OfonoCallState::invalid; return state; } std::string ofono_call_state_to_string(repowerd::OfonoCallState state) { switch (state) { case repowerd::OfonoCallState::active: return "active"; case repowerd::OfonoCallState::alerting: return "alerting"; case repowerd::OfonoCallState::dialing: return "dialing"; case repowerd::OfonoCallState::disconnected: return "disconnected"; case repowerd::OfonoCallState::held: return "held"; case repowerd::OfonoCallState::incoming: return "incoming"; case repowerd::OfonoCallState::waiting: return "waiting"; case repowerd::OfonoCallState::invalid: default: return ""; }; return ""; } repowerd::OfonoCallState get_call_state_from_properties(GVariantIter* properties) { char const* key_cstr{""}; GVariant* value{nullptr}; std::string state; bool done = false; while (!done && g_variant_iter_next(properties, "{&sv}", &key_cstr, &value)) { std::string const key{key_cstr ? key_cstr : ""}; if (key == "State") { state = g_variant_get_string(value, nullptr); done = true; } g_variant_unref(value); } return ofono_call_state_from_string(state); } bool is_call_state_active(repowerd::OfonoCallState call_state) { return call_state == repowerd::OfonoCallState::active || call_state == repowerd::OfonoCallState::alerting || call_state == repowerd::OfonoCallState::dialing; } } repowerd::OfonoVoiceCallService::OfonoVoiceCallService( std::shared_ptr const& log, std::string const& dbus_bus_address) : log{log}, dbus_connection{dbus_bus_address}, dbus_event_loop{"Ofono"}, active_call_handler{null_handler}, no_active_call_handler{null_handler} { } void repowerd::OfonoVoiceCallService::start_processing() { manager_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, ofono_service_name, ofono_manager_interface, nullptr, nullptr, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); voice_call_manager_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, ofono_service_name, ofono_voice_call_manager_interface, nullptr, nullptr, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); voice_call_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, ofono_service_name, ofono_voice_call_interface, nullptr, nullptr, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); dbus_event_loop.enqueue([this] { add_existing_modems(); }).get(); } repowerd::HandlerRegistration repowerd::OfonoVoiceCallService::register_active_call_handler( ActiveCallHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->active_call_handler = handler; }, [this] { this->active_call_handler = null_handler; }}; } repowerd::HandlerRegistration repowerd::OfonoVoiceCallService::register_no_active_call_handler( NoActiveCallHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->no_active_call_handler = handler; }, [this] { this->no_active_call_handler = null_handler; }}; } void repowerd::OfonoVoiceCallService::set_low_power_mode() { dbus_event_loop.enqueue([this] { set_fast_dormancy(true); }); } void repowerd::OfonoVoiceCallService::set_normal_power_mode() { dbus_event_loop.enqueue([this] { set_fast_dormancy(false); }); } std::unordered_set repowerd::OfonoVoiceCallService::tracked_modems() { decltype(modems) ret_modems; dbus_event_loop.enqueue([this,&ret_modems] { ret_modems = modems; }).get(); return ret_modems; } void repowerd::OfonoVoiceCallService::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* signal_name_cstr, GVariant* parameters) { std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; std::string const object_path{object_path_cstr ? object_path_cstr : ""}; std::string const interface_name{interface_name_cstr ? interface_name_cstr : ""}; if (signal_name == "CallAdded") { char const* call_path{""}; GVariantIter* properties; g_variant_get(parameters, "(&oa{sv})", &call_path, &properties); auto const call_state = get_call_state_from_properties(properties); g_variant_iter_free(properties); dbus_CallAdded(call_path, call_state); } else if (signal_name == "CallRemoved") { char const* call_path{""}; g_variant_get(parameters, "(&o)", &call_path); dbus_CallRemoved(call_path); } else if (interface_name == ofono_voice_call_interface && signal_name == "PropertyChanged") { char const* property{""}; GVariant* value; g_variant_get(parameters, "(&sv)", &property, &value); if (std::string{property} == "State") { auto const state_str = g_variant_get_string(value, nullptr); dbus_CallStateChanged(object_path, ofono_call_state_from_string(state_str)); } g_variant_unref(value); } else if (signal_name == "ModemAdded") { char const* modem_path{""}; g_variant_get(parameters, "(&oa{sv})", &modem_path, nullptr); dbus_ModemAdded(modem_path); } else if (signal_name == "ModemRemoved") { char const* modem_path{""}; g_variant_get(parameters, "(&o)", &modem_path); dbus_ModemRemoved(modem_path); } } void repowerd::OfonoVoiceCallService::dbus_CallAdded( std::string const& call_path, OfonoCallState call_state) { log->logDebug(log_tag, "dbus_CallAdded(%s,%s)", call_path.c_str(), ofono_call_state_to_string(call_state).c_str()); update_call_state(call_path, call_state); } void repowerd::OfonoVoiceCallService::dbus_CallRemoved( std::string const& call_path) { log->logDebug(log_tag, "dbus_CallRemoved(%s)", call_path.c_str()); update_call_state(call_path, repowerd::OfonoCallState::invalid); } void repowerd::OfonoVoiceCallService::dbus_CallStateChanged( std::string const& call_path, OfonoCallState call_state) { log->logDebug(log_tag, "dbus_CallStateChanged(%s,%s)", call_path.c_str(), ofono_call_state_to_string(call_state).c_str()); update_call_state(call_path, call_state); } void repowerd::OfonoVoiceCallService::dbus_ModemAdded( std::string const& modem_path) { log->logDebug(log_tag, "dbus_ModemAdded(%s)", modem_path.c_str()); modems.insert(modem_path); } void repowerd::OfonoVoiceCallService::dbus_ModemRemoved( std::string const& modem_path) { log->logDebug(log_tag, "dbus_ModemRemoved(%s)", modem_path.c_str()); modems.erase(modem_path); } void repowerd::OfonoVoiceCallService::update_call_state( std::string const& call_path, OfonoCallState call_state) { auto const old_state = calls[call_path]; if (call_state == repowerd::OfonoCallState::invalid) calls.erase(call_path); else calls[call_path] = call_state; if (!is_call_state_active(old_state) && is_call_state_active(call_state)) { active_call_handler(); } else if (is_call_state_active(old_state) && !is_call_state_active(call_state)) { if (!is_any_call_active()) no_active_call_handler(); } } bool repowerd::OfonoVoiceCallService::is_any_call_active() { return std::any_of( calls.begin(), calls.end(), [this](auto const& kv) { return is_call_state_active(kv.second); }); } void repowerd::OfonoVoiceCallService::add_existing_modems() { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; auto constexpr null_args = nullptr; auto constexpr null_error = nullptr; auto const result = g_dbus_connection_call_sync( dbus_connection, ofono_service_name, "/", ofono_manager_interface, "GetModems", null_args, G_VARIANT_TYPE("(a(oa{sv}))"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, null_error); if (!result) return; GVariantIter* result_modems; g_variant_get(result, "(a(oa{sv}))", &result_modems); char const* modem{""}; while (g_variant_iter_next(result_modems, "(&oa{sv})", &modem, nullptr)) { log->logDebug(log_tag, "add_existing_modems(), %s", modem); modems.insert(modem); } g_variant_iter_free(result_modems); g_variant_unref(result); } void repowerd::OfonoVoiceCallService::set_fast_dormancy(bool fast_dormancy) { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; auto constexpr null_reply_type = nullptr; auto constexpr null_callback = nullptr; auto constexpr null_user_data = nullptr; for (auto const& modem : modems) { log->logDebug(log_tag, "set_fast_dormancy(%s,%s)", modem.c_str(), fast_dormancy ? "true" : "false"); g_dbus_connection_call( dbus_connection, ofono_service_name, modem.c_str(), ofono_radio_settings_interface, "SetProperty", g_variant_new("(sv)", "FastDormancy", g_variant_new_boolean(fast_dormancy)), null_reply_type, G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, null_callback, null_user_data); } } repowerd-2023.07/src/adapters/ofono_voice_call_service.h000066400000000000000000000056541446034100200233050ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/voice_call_service.h" #include "src/core/modem_power_control.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include #include #include namespace repowerd { class Log; enum class OfonoCallState { invalid, active, alerting, dialing, disconnected, held, incoming, waiting}; class OfonoVoiceCallService : public VoiceCallService, public ModemPowerControl { public: OfonoVoiceCallService( std::shared_ptr const& log, std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_active_call_handler( ActiveCallHandler const& handler) override; HandlerRegistration register_no_active_call_handler( NoActiveCallHandler const& handler) override; void set_low_power_mode() override; void set_normal_power_mode() override; std::unordered_set tracked_modems(); private: void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); void dbus_CallAdded(std::string const& call_path, OfonoCallState call_state); void dbus_CallRemoved(std::string const& call_path); void dbus_CallStateChanged(std::string const& call_path, OfonoCallState call_state); void dbus_ModemAdded(std::string const& call_path); void dbus_ModemRemoved(std::string const& call_path); void update_call_state( std::string const& call_path, OfonoCallState call_state); bool is_any_call_active(); void add_existing_modems(); void set_fast_dormancy(bool fast_dormancy); std::shared_ptr const log; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration manager_handler_registration; HandlerRegistration voice_call_manager_handler_registration; HandlerRegistration voice_call_handler_registration; ActiveCallHandler active_call_handler; NoActiveCallHandler no_active_call_handler; std::unordered_map calls; std::unordered_set modems; }; } repowerd-2023.07/src/adapters/path.cpp000066400000000000000000000017201446034100200175420ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "path.h" repowerd::Path::Path(std::string const& path) : path{path} { } repowerd::Path::operator std::string() const { return path; } repowerd::Path repowerd::Path::operator/(std::string const& path) const { return Path{this->path + "/" + path}; } repowerd-2023.07/src/adapters/path.h000066400000000000000000000016531446034100200172140ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { class Path { public: Path(std::string const& path); operator std::string() const; Path operator/(std::string const& path) const; private: std::string path; }; } repowerd-2023.07/src/adapters/real_chrono.cpp000066400000000000000000000017201446034100200211010ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "real_chrono.h" #include void repowerd::RealChrono::sleep_for(std::chrono::nanoseconds t) { std::this_thread::sleep_for(t); } std::chrono::steady_clock::time_point repowerd::RealChrono::steady_now() { return std::chrono::steady_clock::now(); }repowerd-2023.07/src/adapters/real_chrono.h000066400000000000000000000016451446034100200205540ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "chrono.h" namespace repowerd { class RealChrono : public Chrono { public: void sleep_for(std::chrono::nanoseconds t) override; std::chrono::steady_clock::time_point steady_now() override; }; } repowerd-2023.07/src/adapters/real_device_info.cpp000066400000000000000000000020131446034100200220570ustar00rootroot00000000000000/* * Copyright © 2022 UBports Foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #include "real_device_info.h" #include repowerd::RealDeviceInfo::RealDeviceInfo() : deviceinfo(std::make_unique<::DeviceInfo>()) {} std::string repowerd::RealDeviceInfo::name() { return deviceinfo->name(); } bool repowerd::RealDeviceInfo::is_desktop() { return deviceinfo->deviceType() == ::DeviceInfo::Desktop; }repowerd-2023.07/src/adapters/real_device_info.h000066400000000000000000000017441446034100200215360ustar00rootroot00000000000000/* * Copyright © 2022 UBports Foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #pragma once #include "device_info.h" #include class DeviceInfo; namespace repowerd { class RealDeviceInfo : public DeviceInfo { public: RealDeviceInfo(); std::string name() override; bool is_desktop() override; private: std::unique_ptr<::DeviceInfo> deviceinfo; }; }repowerd-2023.07/src/adapters/real_filesystem.cpp000066400000000000000000000045561446034100200220070ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "real_filesystem.h" #include "fd.h" #include #include #include #include #include namespace { bool is_directory(std::string const& path) { struct stat sb; return stat(path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode); } } bool repowerd::RealFilesystem::is_regular_file( std::string const& path) const { struct stat sb; return stat(path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode); } std::unique_ptr repowerd::RealFilesystem::istream( std::string const& path) const { return std::make_unique(path); } std::unique_ptr repowerd::RealFilesystem::ostream( std::string const& path) const { return std::make_unique(path); } std::vector repowerd::RealFilesystem::subdirs( std::string const& path) const { auto dir = opendir(path.c_str()); if (!dir) return {}; dirent* dp; std::vector child_dirs; while ((dp = readdir(dir)) != nullptr) { std::string const entry_name{dp->d_name}; if (entry_name == "." || entry_name == "..") continue; auto const entry = path + "/" + entry_name; if (is_directory(entry)) child_dirs.push_back(entry); } closedir(dir); return child_dirs; } repowerd::Fd repowerd::RealFilesystem::open( char const* pathname, int flags) const { return ::open(pathname, flags); } int repowerd::RealFilesystem::ioctl( int fd, unsigned long request, void* args) const { if (args) return ::ioctl(fd, request, args); else return ::ioctl(fd, request); } repowerd-2023.07/src/adapters/real_filesystem.h000066400000000000000000000023631446034100200214460ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "filesystem.h" namespace repowerd { class RealFilesystem : public Filesystem { public: bool is_regular_file(std::string const& path) const override; std::unique_ptr istream(std::string const& path) const override; std::unique_ptr ostream(std::string const& path) const override; std::vector subdirs(std::string const& path) const override; Fd open(char const* pathname, int flags) const override; int ioctl(int fd, unsigned long request, void* args) const override; }; } repowerd-2023.07/src/adapters/real_temporary_suspend_inhibition.cpp000066400000000000000000000027461446034100200256210ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "real_temporary_suspend_inhibition.h" #include "src/core/system_power_control.h" repowerd::RealTemporarySuspendInhibition::RealTemporarySuspendInhibition( std::shared_ptr const& system_power_control) : system_power_control{system_power_control}, event_loop{"TempSuspendInhibit"}, id{0} { } void repowerd::RealTemporarySuspendInhibition::inhibit_suspend_for( std::chrono::milliseconds timeout, std::string const& name) { auto const cur_id = id++; auto const suspend_id = name + "_" + std::to_string(cur_id); system_power_control->disallow_automatic_suspend(suspend_id); event_loop.schedule_in( timeout, [this, suspend_id] { system_power_control->allow_automatic_suspend(suspend_id); }); } repowerd-2023.07/src/adapters/real_temporary_suspend_inhibition.h000066400000000000000000000024221446034100200252550ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "temporary_suspend_inhibition.h" #include "event_loop.h" #include #include namespace repowerd { class SystemPowerControl; class RealTemporarySuspendInhibition : public TemporarySuspendInhibition { public: RealTemporarySuspendInhibition(std::shared_ptr const& system_power_control); void inhibit_suspend_for(std::chrono::milliseconds timeout, std::string const& name) override; private: std::shared_ptr const system_power_control; EventLoop event_loop; std::atomic id; }; } repowerd-2023.07/src/adapters/repowerd_settings_service.cpp000066400000000000000000000252561446034100200241070ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "repowerd_settings_service.h" #include "event_loop_handler_registration.h" #include "scoped_g_error.h" #include "src/core/infinite_timeout.h" #include "src/core/log.h" #include namespace { char const* const log_tag = "RepowerdSettingsService"; auto const null_arg2_handler = [](auto,auto){}; auto const null_arg3_handler = [](auto,auto,auto){}; auto const null_arg4_handler = [](auto,auto,auto,auto){}; char const* const dbus_repowerd_settings_path = "/com/lomiri/Repowerd/Settings"; char const* const dbus_repowerd_settings_service_name = "com.lomiri.Repowerd.Settings"; char const* const repowerd_settings_service_introspection = R"( )"; repowerd::PowerAction power_action_from_string(std::string const& str) { if (str == "none") return repowerd::PowerAction::none; else if (str == "display-off") return repowerd::PowerAction::display_off; else if (str == "suspend") return repowerd::PowerAction::suspend; else if (str == "power-off") return repowerd::PowerAction::power_off; else throw std::invalid_argument{"Invalid power action: " + str}; } repowerd::PowerSupply power_supply_from_string(std::string const& str) { if (str == "battery") return repowerd::PowerSupply::battery; else if (str == "line-power") return repowerd::PowerSupply::line_power; else throw std::invalid_argument{"Invalid power supply: " + str}; } } repowerd::RepowerdSettingsService::RepowerdSettingsService( std::shared_ptr const& log, std::string const& dbus_bus_address) : log{log}, dbus_connection{dbus_bus_address}, dbus_event_loop{"RepowerdSettingsService"}, set_inactivity_behavior_handler{null_arg4_handler}, set_lid_behavior_handler{null_arg3_handler}, set_critical_power_behavior_handler{null_arg2_handler} { } void repowerd::RepowerdSettingsService::start_processing() { repowerd_handler_registration = dbus_event_loop.register_object_handler( dbus_connection, dbus_repowerd_settings_path, repowerd_settings_service_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { try { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); } catch (std::invalid_argument const& e) { g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, e.what()); } catch (std::exception const& e) { g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, e.what()); } }); dbus_connection.request_name(dbus_repowerd_settings_service_name); } repowerd::HandlerRegistration repowerd::RepowerdSettingsService::register_set_inactivity_behavior_handler( SetInactivityBehaviorHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { set_inactivity_behavior_handler = handler; }, [this] { set_inactivity_behavior_handler = null_arg4_handler; }}; } repowerd::HandlerRegistration repowerd::RepowerdSettingsService::register_set_lid_behavior_handler( SetLidBehaviorHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { set_lid_behavior_handler = handler; }, [this] { set_lid_behavior_handler = null_arg3_handler; }}; } repowerd::HandlerRegistration repowerd::RepowerdSettingsService::register_set_critical_power_behavior_handler( SetCriticalPowerBehaviorHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { set_critical_power_behavior_handler = handler; }, [this] { set_critical_power_behavior_handler = null_arg2_handler; }}; } void repowerd::RepowerdSettingsService::dbus_method_call( GDBusConnection* /*connection*/, gchar const* sender_cstr, gchar const* /*object_path_cstr*/, gchar const* /*interface_name_cstr*/, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation) { std::string const sender{sender_cstr ? sender_cstr : ""}; std::string const method_name{method_name_cstr ? method_name_cstr : ""}; auto const pid = dbus_get_invocation_sender_pid(invocation); if (method_name == "SetInactivityBehavior") { char const* power_action{""}; char const* power_supply{""}; int32_t timeout{-1}; g_variant_get(parameters, "(&s&si)", &power_action, &power_supply, &timeout); dbus_SetInactivityBehavior(sender, power_action, power_supply, timeout, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "SetLidBehavior") { char const* power_action{""}; char const* power_supply{""}; g_variant_get(parameters, "(&s&s)", &power_action, &power_supply); dbus_SetLidBehavior(sender, power_action, power_supply, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "SetCriticalPowerBehavior") { char const* power_action{""}; g_variant_get(parameters, "(&s)", &power_action); dbus_SetCriticalPowerBehavior(sender, power_action, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else { dbus_unknown_method(sender, method_name); g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); } } void repowerd::RepowerdSettingsService::dbus_SetInactivityBehavior( std::string const& sender, std::string const& power_action_str, std::string const& power_supply_str, int32_t power_action_timeout, pid_t pid) { log->logDebug(log_tag, "dbus_SetInactivityBehavior(%s,%s,%s,%d)", sender.c_str(), power_action_str.c_str(), power_supply_str.c_str(), power_action_timeout); auto const timeout = power_action_timeout <= 0 ? repowerd::infinite_timeout : std::chrono::seconds{power_action_timeout}; auto const power_action = power_action_from_string(power_action_str); auto const power_supply = power_supply_from_string(power_supply_str); if (power_action != PowerAction::display_off && power_action != PowerAction::suspend) { throw std::invalid_argument{"Invalid power action for inactivity: " + power_action_str}; } set_inactivity_behavior_handler(power_action, power_supply, timeout, pid); } void repowerd::RepowerdSettingsService::dbus_SetLidBehavior( std::string const& sender, std::string const& power_action_str, std::string const& power_supply_str, pid_t pid) { log->logDebug(log_tag, "dbus_SetLidBehavior(%s,%s,%s)", sender.c_str(), power_action_str.c_str(), power_supply_str.c_str()); auto const power_action = power_action_from_string(power_action_str); auto const power_supply = power_supply_from_string(power_supply_str); if (power_action != PowerAction::none && power_action != PowerAction::suspend) { throw std::invalid_argument{"Invalid power action for lid: " + power_action_str}; } set_lid_behavior_handler(power_action, power_supply, pid); } void repowerd::RepowerdSettingsService::dbus_SetCriticalPowerBehavior( std::string const& sender, std::string const& power_action_str, pid_t pid) { log->logDebug(log_tag, "dbus_SetCriticalPowerBehavior(%s,%s)", sender.c_str(), power_action_str.c_str()); auto const power_action = power_action_from_string(power_action_str); if (power_action != PowerAction::suspend && power_action != PowerAction::power_off) { throw std::invalid_argument{"Invalid power action for critical power: " + power_action_str}; } set_critical_power_behavior_handler(power_action, pid); } void repowerd::RepowerdSettingsService::dbus_unknown_method( std::string const& sender, std::string const& name) { log->logWarning(log_tag, "dbus_unknown_method(%s,%s)", sender.c_str(), name.c_str()); } pid_t repowerd::RepowerdSettingsService::dbus_get_invocation_sender_pid( GDBusMethodInvocation* invocation) { int constexpr timeout = 1000; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const sender = g_dbus_method_invocation_get_sender(invocation); auto const result = g_dbus_connection_call_sync( dbus_connection, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetConnectionUnixProcessID", g_variant_new("(s)", sender), G_VARIANT_TYPE("(u)"), G_DBUS_CALL_FLAGS_NONE, timeout, null_cancellable, error); if (!result) { log->logWarning(log_tag, "failed to get pid of '%s': %s", sender, error.message_str().c_str()); return -1; } guint pid; g_variant_get(result, "(u)", &pid); g_variant_unref(result); return pid; } repowerd-2023.07/src/adapters/repowerd_settings_service.h000066400000000000000000000057141446034100200235510ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/client_settings.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include #include #include namespace repowerd { class Log; class RepowerdSettingsService : public ClientSettings { public: RepowerdSettingsService( std::shared_ptr const& log, std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_set_inactivity_behavior_handler( SetInactivityBehaviorHandler const& handler) override; HandlerRegistration register_set_lid_behavior_handler( SetLidBehaviorHandler const& handler) override; HandlerRegistration register_set_critical_power_behavior_handler( SetCriticalPowerBehaviorHandler const& handler) override; private: void dbus_method_call( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation); void dbus_SetInactivityBehavior( std::string const& sender, std::string const& power_action, std::string const& power_supply, int32_t power_action_timeout, pid_t pid); void dbus_SetLidBehavior( std::string const& sender, std::string const& power_action, std::string const& power_supply, pid_t pid); void dbus_SetCriticalPowerBehavior( std::string const& sender, std::string const& power_action, pid_t pid); void dbus_unknown_method(std::string const& sender, std::string const& name); pid_t dbus_get_invocation_sender_pid(GDBusMethodInvocation* invocation); std::shared_ptr const log; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; SetInactivityBehaviorHandler set_inactivity_behavior_handler; SetLidBehaviorHandler set_lid_behavior_handler; SetCriticalPowerBehaviorHandler set_critical_power_behavior_handler; // These need to be at the end, so that handlers are unregistered first on // destruction, to avoid accessing other members if an event arrives // on destruction. HandlerRegistration repowerd_handler_registration; }; } repowerd-2023.07/src/adapters/scoped_g_error.h000066400000000000000000000025161446034100200212530ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { struct ScopedGError { ScopedGError() : g_error{nullptr} {} ~ScopedGError() { if (g_error) g_error_free(g_error); } std::string message_str() const { if (g_error && g_error->message) return g_error->message; else return {}; } bool is_set() const { return g_error != nullptr; } operator GError**() { return &g_error; } private: GError* g_error; ScopedGError(ScopedGError const&) = delete; ScopedGError& operator=(ScopedGError const&) = delete; }; } repowerd-2023.07/src/adapters/sensorfw/000077500000000000000000000000001446034100200177505ustar00rootroot00000000000000repowerd-2023.07/src/adapters/sensorfw/sensorfw_common.cpp000066400000000000000000000176371446034100200237100ustar00rootroot00000000000000/* * Copyright © 2020 UBports foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #include "sensorfw_common.h" #include "socketreader.h" namespace { char const* const log_tag = "Sensorfw"; char const* const dbus_sensorfw_name = "com.nokia.SensorService"; char const* const dbus_sensorfw_path = "/SensorManager"; char const* const dbus_sensorfw_interface = "local.SensorManager"; } repowerd::Sensorfw::Sensorfw( std::shared_ptr const& log, std::string const& dbus_bus_address, std::string const& name, PluginType const& plugin) : log{log}, dbus_connection{dbus_bus_address}, dbus_event_loop{name}, m_socket(std::make_shared()), m_plugin(plugin), m_pluginPath(nullptr, free), m_pid(getpid()), m_gsource(nullptr, g_source_unref) { if (!load_plugin()) throw std::runtime_error("Could not create sensorfw backend"); request_sensor(); char *new_str; if (asprintf(&new_str,"%s/%s", dbus_sensorfw_path, plugin_string()) == -1) log->logWarning(log_tag, "Unable to create the plugin path."); else m_pluginPath.reset(new_str); log->logDebug(log_tag, "Got plugin_string %s", plugin_string()); log->logDebug(log_tag, "Got plugin_interface %s", plugin_interface()); log->logDebug(log_tag, "Got plugin_path %s", plugin_path()); dbus_event_loop.enqueue([this]{ m_socket->initiateConnection(m_sessionid); }).get(); } repowerd::Sensorfw::~Sensorfw() { stop(); release_sensor(); dbus_event_loop.enqueue([this]{ m_socket->dropConnection(); }).get(); } const char* repowerd::Sensorfw::plugin_string() const { switch (m_plugin) { case PluginType::LIGHT: return "alssensor"; case PluginType::PROXIMITY: return "proximitysensor"; } return ""; } const char* repowerd::Sensorfw::plugin_interface() const { switch (m_plugin) { case PluginType::LIGHT: return "local.ALSSensor"; case PluginType::PROXIMITY: return "local.ProximitySensor"; } return ""; } const char* repowerd::Sensorfw::plugin_path() const { if (!m_pluginPath) return ""; return m_pluginPath.get(); } bool repowerd::Sensorfw::load_plugin() { int constexpr timeout_default = 10000; g_autoptr(GError) err = NULL; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_sensorfw_name, dbus_sensorfw_path, dbus_sensorfw_interface, "loadPlugin", g_variant_new("(s)", plugin_string()), G_VARIANT_TYPE("(b)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, NULL, &err); if (err != NULL) { log->logWarning(log_tag, "failed to call load_plugin: %s", err->message); g_variant_unref(result); return false; } gboolean the_result; g_variant_get(result, "(b)", &the_result); g_variant_unref(result); return the_result; } void repowerd::Sensorfw::request_sensor() { int constexpr timeout_default = 5000; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_sensorfw_name, dbus_sensorfw_path, dbus_sensorfw_interface, "requestSensor", g_variant_new("(sx)", plugin_string(), m_pid), G_VARIANT_TYPE("(i)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, NULL, NULL); if (!result) { log->logWarning(log_tag, "failed to call request_sensor"); return; } gint32 the_result; g_variant_get(result, "(i)", &the_result); g_variant_unref(result); m_sessionid = the_result; log->logDebug(log_tag, "Got new plugin for %s with pid %i and session %i", plugin_string(), m_pid, m_sessionid); } bool repowerd::Sensorfw::release_sensor() { int constexpr timeout_default = 1000; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_sensorfw_name, dbus_sensorfw_path, dbus_sensorfw_interface, "releaseSensor", g_variant_new("(six)", plugin_string(), m_sessionid, m_pid), G_VARIANT_TYPE("(b)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, NULL, NULL); if (!result) { log->logWarning(log_tag, "failed to release SensorfwSensor"); return false; } gboolean the_result; g_variant_get(result, "(b)", &the_result); g_variant_unref(result); return the_result; } gboolean repowerd::Sensorfw::static_data_recieved(GSocket * /* socket */, GIOCondition cond, gpointer user_data) { if (! (cond & G_IO_IN)) return G_SOURCE_CONTINUE; auto self = reinterpret_cast(user_data); self->data_recived_impl(); return G_SOURCE_CONTINUE; } void repowerd::Sensorfw::start() { if (m_gsource) return; GSocket *socket = g_socket_connection_get_socket(m_socket->socket()); m_gsource = std::unique_ptr { g_socket_create_source(socket, G_IO_IN, /* cancellable */ NULL), g_source_unref }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" g_source_set_callback( m_gsource.get(), reinterpret_cast(&Sensorfw::static_data_recieved), this, /* notify */ NULL); #pragma GCC diagnostic pop g_source_attach(m_gsource.get(), g_main_context_get_thread_default()); int constexpr timeout_default = 5000; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_sensorfw_name, plugin_path(), plugin_interface(), "start", g_variant_new("(i)", m_sessionid), NULL, G_DBUS_CALL_FLAGS_NONE, timeout_default, NULL, NULL); if (!result) { log->logWarning(log_tag, "failed to start SensorfwSensor"); stop(); return; } g_variant_unref(result); } void repowerd::Sensorfw::stop() { if (!m_gsource) return; int constexpr timeout_default = 1000; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_sensorfw_name, plugin_path(), plugin_interface(), "stop", g_variant_new("(i)", m_sessionid), NULL, G_DBUS_CALL_FLAGS_NONE, timeout_default, NULL, NULL); if (!result) { log->logWarning(log_tag, "failed to stop SensorfwSensor"); } else { g_variant_unref(result); } g_source_destroy(m_gsource.get()); m_gsource.reset(); } void repowerd::Sensorfw::set_interval(int interval) { int constexpr timeout_default = 1000; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_sensorfw_name, plugin_path(), plugin_interface(), "setInterval", g_variant_new("(ii)", m_sessionid, interval), NULL, G_DBUS_CALL_FLAGS_NONE, timeout_default, NULL, NULL); if (!result) { log->logWarning(log_tag, "set_interval() failed to releaseSensor"); return; } g_variant_unref(result); } repowerd-2023.07/src/adapters/sensorfw/sensorfw_common.h000066400000000000000000000040001446034100200233310ustar00rootroot00000000000000/* * Copyright © 2020 UBports foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #include #include #include #include "src/adapters/dbus_connection_handle.h" #include "src/adapters/dbus_event_loop.h" #include "src/core/log.h" #pragma once class SocketReader; namespace repowerd { class Sensorfw { public: enum PluginType { LIGHT, PROXIMITY }; Sensorfw( std::shared_ptr const& log, std::string const& dbus_bus_address, std::string const& name, PluginType const& plugin); virtual ~Sensorfw(); protected: virtual void data_recived_impl() = 0; void set_interval(int interval = 10); void start(); void stop(); std::shared_ptr const log; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; std::shared_ptr m_socket; private: void request_sensor(); bool release_sensor(); bool load_plugin(); const char* plugin_string() const; const char* plugin_interface() const; const char* plugin_path() const; static gboolean static_data_recieved(GSocket * socket, GIOCondition cond, gpointer user_data); HandlerRegistration dbus_signal_handler_registration; PluginType m_plugin; std::unique_ptr m_pluginPath; pid_t m_pid; int m_sessionid; std::unique_ptr m_gsource; }; } repowerd-2023.07/src/adapters/sensorfw/sensorfw_light_sensor.cpp000066400000000000000000000042501446034100200251030ustar00rootroot00000000000000/* * Copyright © 2020 UBports foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #include "sensorfw_light_sensor.h" #include "src/adapters/event_loop_handler_registration.h" #include "socketreader.h" #include namespace { auto const null_handler = [](double){}; char const* const log_tag = "SensorfwLightSensor"; } repowerd::SensorfwLightSensor::SensorfwLightSensor( std::shared_ptr const& log, std::string const& dbus_bus_address) : Sensorfw(log, dbus_bus_address, "Light", PluginType::LIGHT), handler{null_handler} { } repowerd::HandlerRegistration repowerd::SensorfwLightSensor::register_light_handler( LightHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler]{ this->handler = handler; }, [this]{ this->handler = null_handler; }}; } void repowerd::SensorfwLightSensor::enable_light_events() { dbus_event_loop.enqueue( [this] { start(); }).get(); } void repowerd::SensorfwLightSensor::disable_light_events() { dbus_event_loop.enqueue( [this] { stop(); }).get(); } void repowerd::SensorfwLightSensor::data_recived_impl() { std::vector values; if(!m_socket->read(values)) return; if (values[0].value_ == 0) { /* Sometimes SensorFW sends a bogus value 0 on start. Workaround that by * skipping that value. */ log->log(log_tag, "Skip bobus value 0 from SensorFW."); return; } handler(values[0].value_); } repowerd-2023.07/src/adapters/sensorfw/sensorfw_light_sensor.h000066400000000000000000000023301446034100200245450ustar00rootroot00000000000000/* * Copyright © 2020 UBports foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #pragma once #include "src/adapters/light_sensor.h" #include "sensorfw_common.h" namespace repowerd { class SensorfwLightSensor : public LightSensor, public Sensorfw { public: SensorfwLightSensor(std::shared_ptr const& log, std::string const& dbus_bus_address); HandlerRegistration register_light_handler(LightHandler const& handler) override; void enable_light_events() override; void disable_light_events() override; private: void data_recived_impl() override; LightHandler handler; }; } repowerd-2023.07/src/adapters/sensorfw/sensorfw_proximity_sensor.cpp000066400000000000000000000043231446034100200260410ustar00rootroot00000000000000/* * Copyright © 2020 UBports foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #include "sensorfw_proximity_sensor.h" #include "src/adapters/event_loop_handler_registration.h" #include "socketreader.h" #include namespace { auto const null_handler = [](repowerd::ProximityState){}; } repowerd::SensorfwProximitySensor::SensorfwProximitySensor( std::shared_ptr const& log, std::string const& dbus_bus_address) : Sensorfw(log, dbus_bus_address, "Proximity", PluginType::PROXIMITY), m_handler{null_handler}, m_state{ProximityState::far} { } repowerd::HandlerRegistration repowerd::SensorfwProximitySensor::register_proximity_handler( ProximityHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler]{ this->m_handler = handler; }, [this]{ this->m_handler = null_handler; }}; } void repowerd::SensorfwProximitySensor::enable_proximity_events() { dbus_event_loop.enqueue( [this] { start(); }).get(); } void repowerd::SensorfwProximitySensor::disable_proximity_events() { dbus_event_loop.enqueue( [this] { stop(); }).get(); } void repowerd::SensorfwProximitySensor::data_recived_impl() { std::vector values; if(m_socket->read(values)) { m_state = values[0].withinProximity_ ? ProximityState::near : ProximityState::far; } else { m_state = ProximityState::far; } m_handler(m_state); } repowerd::ProximityState repowerd::SensorfwProximitySensor::proximity_state() { return m_state; } repowerd-2023.07/src/adapters/sensorfw/sensorfw_proximity_sensor.h000066400000000000000000000025311446034100200255050ustar00rootroot00000000000000/* * Copyright © 2020 UBports foundation * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #pragma once #include "src/core/proximity_sensor.h" #include "sensorfw_common.h" namespace repowerd { class SensorfwProximitySensor : public ProximitySensor, public Sensorfw { public: SensorfwProximitySensor(std::shared_ptr const& log, std::string const& dbus_bus_address); HandlerRegistration register_proximity_handler( ProximityHandler const& handler) override; ProximityState proximity_state() override; void enable_proximity_events() override; void disable_proximity_events() override; private: void data_recived_impl() override; ProximityHandler m_handler; repowerd::ProximityState m_state; }; } repowerd-2023.07/src/adapters/sensorfw/socketreader.cpp000066400000000000000000000121641446034100200231330ustar00rootroot00000000000000/** @file socketreader.cpp @brief SocketReader helper class for sensor interface

Copyright 2022 UBports Foundation. Copyright (C) 2009-2010 Nokia Corporation @author Timo Rongas @author Antti Virtanen This file is part of Sensord. Sensord is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Sensord is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Sensord. If not, see .

*/ #include "socketreader.h" #include #include #include #include #include #include #include #include #include #include #include const char* SocketReader::channelIDString = "_SENSORCHANNEL_"; SocketReader::SocketReader() : socket_(NULL), tagRead_(false) { } SocketReader::~SocketReader() { if (socket_) { dropConnection(); } } bool SocketReader::initiateConnection(int sessionId) { if (socket_ != NULL) { g_debug("attempting to initiate connection on connected socket"); return false; } const std::string SOCKET_NAME {"/var/run/sensord.sock"}; const char* env = getenv("SENSORFW_SOCKET_PATH"); auto full_path = env ? env : "" + SOCKET_NAME; auto sock_addr = std::unique_ptr{ g_unix_socket_address_new(full_path.c_str()), g_object_unref}; auto sock_client = std::unique_ptr{ g_socket_client_new(), g_object_unref}; g_autoptr(GError) err = NULL; socket_ = g_socket_client_connect( sock_client.get(), G_SOCKET_CONNECTABLE(sock_addr.get()), /* cancellable */ NULL, &err); if (!socket_) { g_debug("Failed to connect to socket: %s", err->message); return false; } istream_ = g_io_stream_get_input_stream(G_IO_STREAM(socket_)); ostream_ = g_io_stream_get_output_stream(G_IO_STREAM(socket_)); if (!g_output_stream_write_all( ostream_, (const char*)&sessionId, sizeof(sessionId), /* (out) bytes_written */ NULL, /* cancellable */ NULL, &err)) { g_debug("[SOCKETREADER]: SessionId write failed: %s", err->message); g_clear_error(&err); } if (!g_output_stream_flush(ostream_, /* cancellable */ NULL, &err)) { g_debug("[SOCKETREADER]: flush write failed: %s", err->message); g_clear_error(&err); } readSocketTag(); return true; } bool SocketReader::dropConnection() { if (!socket_) return false; /* These are owned by socket */ istream_ = NULL; ostream_ = NULL; g_io_stream_close( G_IO_STREAM(socket_), /* cancellable */ NULL, /* (out) err */ NULL); g_object_unref(socket_); socket_ = NULL; tagRead_ = false; return true; } GSocketConnection* SocketReader::socket() { return socket_; } bool SocketReader::readSocketTag() { tagRead_ = g_input_stream_skip( istream_, /* count */ 1, /* cancellable */ NULL, /* (out) error */ NULL); return true; } bool SocketReader::read(void* buffer, int size) { int bytesRead = 0; while(bytesRead < size) { g_autoptr(GError) err = NULL; int bytes = g_input_stream_read( istream_, (char *)buffer + bytesRead, size - bytesRead, /* cancellable */ NULL, /* (out) err */ &err); if (err) { g_warning("Failed to read from socket: %s. Unexpected things might occur.", err->message); return false; } if(bytes == 0) { // This is EOF. No further reading possible. break; } if(bytes < 1) return false; bytesRead += bytes; } return (bytesRead > 0); } bool SocketReader::isConnected() { return ( socket_ && g_socket_connection_is_connected(socket_) && !g_io_stream_is_closed(G_IO_STREAM(socket_))); } void SocketReader::skipAll() { while (g_pollable_input_stream_is_readable(G_POLLABLE_INPUT_STREAM(istream_))) { g_autoptr(GError) err = NULL; auto ret = g_input_stream_skip( istream_, /* count */ G_MAXSSIZE, /* cancellable */ NULL, /* (out) error */ &err); if (err) { g_warning("Cannot skip the stream: %s. Unexpected things might occur.", err->message); break; } if (ret == 0) { // This is EOF. break; } } } repowerd-2023.07/src/adapters/sensorfw/socketreader.h000066400000000000000000000126121446034100200225760ustar00rootroot00000000000000/** @file socketreader.h @brief SocketReader helper class for sensor interface

Copyright 2022 UBports Foundation. Copyright (C) 2009-2010 Nokia Corporation @author Timo Rongas @author Antti Virtanen This file is part of Sensord. Sensord is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Sensord is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Sensord. If not, see .

*/ #pragma once #include #include #include #include class TimedData { public: /** * Constructor * * @param timestamp monotonic time (microsec) */ TimedData(const uint64_t& timestamp) : timestamp_(timestamp) {} uint64_t timestamp_; /**< monotonic time (microsec) */ }; class TimedUnsigned : public TimedData { public: /** * Default constructor. */ TimedUnsigned() : TimedData(0), value_(0) {} /** * Constructor. * * @param timestamp timestamp as monotonic time (microsec). * @param value value of the measurement. */ TimedUnsigned(const uint64_t& timestamp, unsigned value) : TimedData(timestamp), value_(value) {} unsigned value_; /**< Measurement value. */ }; class ProximityData : public TimedUnsigned { public: /** * Default constructor. */ ProximityData() : TimedUnsigned(), withinProximity_(false) {} /** * Constructor * * @param timestamp timestamp as monotonic time (microsec). * @param value raw proximity value. * @param withinProximity is there an object within proximity. */ ProximityData(const uint64_t& timestamp, unsigned int value, bool withinProximity) : TimedUnsigned(timestamp, value), withinProximity_(withinProximity) {} bool withinProximity_; /**< is an object within proximity or not */ }; /** * @brief Helper class for reading socket datachannel from sensord * * SocketReader provides common handler for all sensors using socket * data channel. It is used by AbstractSensorChannelInterface to maintain * the socket connection to the server. */ class SocketReader { public: /** * Constructor. */ SocketReader(); /** * Destructor. */ ~SocketReader(); /** * Initiates new data socket connection. * * @param sessionId ID for the current session. * @return was the connection established successfully. */ bool initiateConnection(int sessionId); /** * Drops socket connection. * @return was the connection successfully closed. */ bool dropConnection(); /** * Provides access to the internal GSocketConnection for direct reading. * * @return Pointer to the internal GSocketConnection. Pointer can be \c NULL * if \c initiateConnection() has not been called successfully. */ GSocketConnection* socket(); /** * Attempt to read given number of bytes from the socket. * * @param size Number of bytes to read. * @param buffer Location for storing the data. * @return was given amount of bytes read succesfully. */ bool read(void* buffer, int size); /** * Attempt to read objects from the sockets. The call blocks until * there are minimum amount of expected bytes availabled in the socket. * * @param values Vector to which objects will be appended. * @tparam T type of expected object in the stream. * @return true if atleast one object was read. */ template bool read(std::vector& values); /** * Returns whether the socket is currently connected. * * @return is socket connected. */ bool isConnected(); private: /** * Prefix text needed to be written to the sensor daemon socket connection * when establishing new session. */ static const char* channelIDString; /** * Reads initial magic byte from the fresh connection. */ bool readSocketTag(); /** * Skip any readable content on the socket. */ void skipAll(); GSocketConnection* socket_; /**< socket data connection to sensord */ GInputStream* istream_; /**< input of socket. owned by socket. */ GOutputStream* ostream_; /**< output of socket. owned by socket. */ bool tagRead_; /**< is initial magic byte read from the socket */ }; template bool SocketReader::read(std::vector& values) { if (!socket_) { return false; } unsigned int count; if(!read((void*)&count, sizeof(unsigned int))) { skipAll(); return false; } if(count > 1000) { g_warning("Too many samples waiting in socket. Flushing it to empty"); skipAll(); return false; } values.resize(values.size() + count); if(!read((void*)values.data(), sizeof(T) * count)) { g_warning("Error occured while reading data from socket"); skipAll(); return false; } return true; } repowerd-2023.07/src/adapters/sysfs_backlight.cpp000066400000000000000000000077401446034100200217750ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "sysfs_backlight.h" #include "filesystem.h" #include "path.h" #include "src/core/log.h" #include #include #include #include #include namespace { char const* const log_tag = "SysfsBacklight"; struct CompareBacklightPriority { CompareBacklightPriority(repowerd::Filesystem& filesystem) : filesystem{filesystem} { } int get_backlight_priority(repowerd::Path const& backlight_dir) { auto istream = filesystem.istream(backlight_dir/"type"); std::string type; *istream >> type; if (type == "firmware") return 1; else if (type == "platform") return 2; else if (type == "raw") return 3; return 10; } bool operator()(repowerd::Path const& b1, repowerd::Path const& b2) { return get_backlight_priority(b1) < get_backlight_priority(b2); } repowerd::Filesystem& filesystem; }; repowerd::Path determine_sysfs_backlight_dir(repowerd::Filesystem& filesystem) { repowerd::Path const sys_backlight_root{"/sys/class/backlight"}; repowerd::Path const sys_led_backlight{"/sys/class/leds/lcd-backlight"}; std::vector backlights; for (auto const& dir : filesystem.subdirs(sys_backlight_root)) { if (filesystem.is_regular_file(repowerd::Path{dir}/"brightness")) backlights.push_back(dir); } if (!backlights.empty()) { std::stable_sort(backlights.begin(), backlights.end(), CompareBacklightPriority(filesystem)); return backlights.front(); } if (filesystem.is_regular_file(sys_led_backlight/"brightness")) return sys_led_backlight; throw std::runtime_error("Couldn't find backlight in sysfs"); } int determine_max_brightness( repowerd::Filesystem& filesystem, repowerd::Path const& backlight_dir) { auto istream = filesystem.istream(backlight_dir/"max_brightness"); int max_brightness = 0; *istream >> max_brightness; return max_brightness; } } repowerd::SysfsBacklight::SysfsBacklight( std::shared_ptr const& log, std::shared_ptr const& filesystem) : filesystem{filesystem}, sysfs_backlight_dir{determine_sysfs_backlight_dir(*filesystem)}, sysfs_brightness_file{sysfs_backlight_dir/"brightness"}, max_brightness{determine_max_brightness(*filesystem, sysfs_backlight_dir)}, last_set_brightness{-1.0} { log->logDebug(log_tag, "Using backlight %s", std::string{sysfs_backlight_dir}.c_str()); } void repowerd::SysfsBacklight::set_brightness(double value) { auto ostream = filesystem->ostream(sysfs_brightness_file); *ostream << absolute_brightness_for(value); ostream->flush(); last_set_brightness = value; } double repowerd::SysfsBacklight::get_brightness() { auto istream = filesystem->istream(sysfs_brightness_file); int abs_brightness = 0; *istream >> abs_brightness; if (absolute_brightness_for(last_set_brightness) == abs_brightness) return last_set_brightness; else return static_cast(abs_brightness) / max_brightness; } int repowerd::SysfsBacklight::absolute_brightness_for(double rel_brightness) { return static_cast(round(rel_brightness * max_brightness)); } repowerd-2023.07/src/adapters/sysfs_backlight.h000066400000000000000000000025221446034100200214330ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "backlight.h" #include "path.h" #include #include namespace repowerd { class Log; class Filesystem; class SysfsBacklight : public Backlight { public: SysfsBacklight( std::shared_ptr const& log, std::shared_ptr const& filesystem); void set_brightness(double) override; double get_brightness() override; private: int absolute_brightness_for(double relative_brightness); std::shared_ptr const filesystem; Path const sysfs_backlight_dir; Path const sysfs_brightness_file; int const max_brightness; double last_set_brightness; }; } repowerd-2023.07/src/adapters/syslog_log.cpp000066400000000000000000000026531446034100200207750ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "syslog_log.h" #include #include #include repowerd::SyslogLog::SyslogLog(repowerd::LogLevel threshold) : repowerd::Log::Log(threshold) { openlog("repowerd", LOG_PID, LOG_DAEMON); } repowerd::SyslogLog::~SyslogLog() { closelog(); } void repowerd::SyslogLog::logOutput(repowerd::LogLevel level, char const* tag, char const* format, va_list ap) { std::string const format_str = std::string{tag} + ": " + format; int priority; switch (level) { case LogLevel::Warning: priority = LOG_WARNING; break; case LogLevel::Info: priority = LOG_INFO; break; default: priority = LOG_DEBUG; } vsyslog(priority, format_str.c_str(), ap); } repowerd-2023.07/src/adapters/syslog_log.h000066400000000000000000000017001446034100200204320ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/log.h" namespace repowerd { class SyslogLog : public Log { public: SyslogLog(LogLevel threshold); ~SyslogLog(); void logOutput(LogLevel level, char const* tag, char const* format, va_list ap) override; }; } repowerd-2023.07/src/adapters/temporary_suspend_inhibition.h000066400000000000000000000022611446034100200242530ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class TemporarySuspendInhibition { public: virtual ~TemporarySuspendInhibition() = default; virtual void inhibit_suspend_for(std::chrono::milliseconds timeout, std::string const& name) = 0; protected: TemporarySuspendInhibition() = default; TemporarySuspendInhibition(TemporarySuspendInhibition const&) = delete; TemporarySuspendInhibition& operator=(TemporarySuspendInhibition const&) = delete; }; } repowerd-2023.07/src/adapters/timerfd_wakeup_service.cpp000066400000000000000000000077231446034100200233450ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "timerfd_wakeup_service.h" #include "event_loop_handler_registration.h" #include "src/core/log.h" #include #include namespace { char const* const log_tag = "Timerfd"; auto null_handler = [](auto){}; timespec to_timespec(std::chrono::system_clock::time_point const& tp) { auto d = tp.time_since_epoch(); auto const sec = std::chrono::duration_cast(d); timespec ts; ts.tv_sec = sec.count(); ts.tv_nsec = std::chrono::duration_cast(d - sec).count(); return ts; } } repowerd::TimerfdWakeupService::TimerfdWakeupService(std::shared_ptr const& log) : timerfd_fd{timerfd_create(CLOCK_REALTIME_ALARM, TFD_CLOEXEC)}, cookie_pool{1}, wakeup_handler{null_handler}, event_loop{"Wakeup"} { if (timerfd_fd == -1) { log->logWarning(log_tag, "Failed to create timerfd with CLOCK_REALTIME_ALARM, trying CLOCK_REALTIME PLEASE note this will not wake up the device from suspend!"); timerfd_fd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC); } if (timerfd_fd == -1) throw std::system_error{errno, std::system_category(), "Failed to create timerfd"}; event_loop.watch_fd( timerfd_fd, [this] { auto const wakeup = *wakeups.begin(); cookie_pool.remove(std::stoull(wakeup.second)); wakeups.erase(wakeups.begin()); reset_timerfd(); wakeup_handler(wakeup.second); }); reset_timerfd(); } std::string repowerd::TimerfdWakeupService::schedule_wakeup_at( std::chrono::system_clock::time_point tp) { std::string cookie; event_loop.enqueue( [this,tp,&cookie] { cookie = std::to_string(cookie_pool.generate()); wakeups.insert({tp, cookie}); reset_timerfd(); }).wait(); return cookie; } void repowerd::TimerfdWakeupService::cancel_wakeup(std::string const& cookie) { event_loop.enqueue( [this,&cookie] { for (auto iter = wakeups.begin(); iter != wakeups.end(); ++iter) { if (iter->second == cookie) { cookie_pool.remove(std::stoull(cookie)); wakeups.erase(iter); break; } } reset_timerfd(); }).wait(); } repowerd::HandlerRegistration repowerd::TimerfdWakeupService::register_wakeup_handler( WakeupHandler const& handler) { return EventLoopHandlerRegistration{ event_loop, [this, &handler] { wakeup_handler = handler; }, [this] { wakeup_handler = null_handler; }}; } unsigned int repowerd::TimerfdWakeupService::num_stored_elements() { unsigned int elements = 0; event_loop.enqueue( [this,&elements] { elements = cookie_pool.size() + wakeups.size(); }).wait(); return elements; } void repowerd::TimerfdWakeupService::reset_timerfd() { timespec next_wakeup; if (wakeups.empty()) next_wakeup = {0, 0}; else next_wakeup = to_timespec(wakeups.begin()->first); timespec const interval{0,0}; itimerspec const spec{interval, next_wakeup}; timerfd_settime(timerfd_fd, TFD_TIMER_ABSTIME, &spec, nullptr); } repowerd-2023.07/src/adapters/timerfd_wakeup_service.h000066400000000000000000000027751446034100200230140ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "wakeup_service.h" #include "event_loop.h" #include "fd.h" #include "unique_random_pool.h" #include namespace repowerd { class Log; class TimerfdWakeupService : public WakeupService { public: TimerfdWakeupService(std::shared_ptr const& log); std::string schedule_wakeup_at(std::chrono::system_clock::time_point tp) override; void cancel_wakeup(std::string const& cookie) override; HandlerRegistration register_wakeup_handler(WakeupHandler const& handler) override; // For testing only unsigned int num_stored_elements(); private: void reset_timerfd(); Fd timerfd_fd; UniqueRandomPool cookie_pool; WakeupHandler wakeup_handler; std::multimap wakeups; EventLoop event_loop; }; } repowerd-2023.07/src/adapters/ubuntu_light_sensor.cpp000066400000000000000000000046231446034100200227150ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "ubuntu_light_sensor.h" #include "event_loop_handler_registration.h" #include namespace { auto const null_handler = [](double){}; } repowerd::UbuntuLightSensor::UbuntuLightSensor() : sensor{ua_sensors_light_new()}, event_loop{"Light"}, handler{null_handler}, enabled{false} { if (!sensor) throw std::runtime_error("Failed to allocate light sensor"); ua_sensors_light_set_reading_cb(sensor, static_sensor_reading_callback, this); } repowerd::HandlerRegistration repowerd::UbuntuLightSensor::register_light_handler( LightHandler const& handler) { return EventLoopHandlerRegistration{ event_loop, [this, &handler]{ this->handler = handler; }, [this]{ this->handler = null_handler; }}; } void repowerd::UbuntuLightSensor::enable_light_events() { event_loop.enqueue( [this] { if (!enabled) { ua_sensors_light_enable(sensor); enabled = true; } }).get(); } void repowerd::UbuntuLightSensor::disable_light_events() { event_loop.enqueue( [this] { if (enabled) { ua_sensors_light_disable(sensor); enabled = false; } }).get(); } void repowerd::UbuntuLightSensor::static_sensor_reading_callback( UASLightEvent* event, void* context) { auto const uls = static_cast(context); float light_value{0.0f}; uas_light_event_get_light(event, &light_value); uls->event_loop.enqueue([uls, light_value] { uls->handle_light_event(light_value); }); } void repowerd::UbuntuLightSensor::handle_light_event(double light) { handler(light); } repowerd-2023.07/src/adapters/ubuntu_light_sensor.h000066400000000000000000000025001446034100200223520ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "light_sensor.h" #include "event_loop.h" #include namespace repowerd { class UbuntuLightSensor : public LightSensor { public: UbuntuLightSensor(); HandlerRegistration register_light_handler(LightHandler const& handler) override; void enable_light_events() override; void disable_light_events() override; private: static void static_sensor_reading_callback(UASLightEvent* event, void* context); void handle_light_event(double light_value); UASensorsLight* const sensor; EventLoop event_loop; LightHandler handler; bool enabled; }; } repowerd-2023.07/src/adapters/ubuntu_performance_booster.cpp000066400000000000000000000034361446034100200242540ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "ubuntu_performance_booster.h" #include "src/core/log.h" namespace { char const* const log_tag = "UbuntuPerformanceBooster"; void u_hardware_booster_deleter(UHardwareBooster* booster) { if (booster) u_hardware_booster_unref(booster); } } repowerd::UbuntuPerformanceBooster::UbuntuPerformanceBooster( std::shared_ptr const& log) : log{log}, booster{u_hardware_booster_new(), u_hardware_booster_deleter} { if (!booster) throw std::runtime_error{"Failed to create ubuntu performance booster"}; } repowerd::UbuntuPerformanceBooster::~UbuntuPerformanceBooster() = default; void repowerd::UbuntuPerformanceBooster::enable_interactive_mode() { log->logDebug(log_tag, "enable_interactive_mode()"); u_hardware_booster_enable_scenario( booster.get(), U_HARDWARE_BOOSTER_SCENARIO_USER_INTERACTION); } void repowerd::UbuntuPerformanceBooster::disable_interactive_mode() { log->logDebug(log_tag, "disable_interactive_mode()"); u_hardware_booster_disable_scenario( booster.get(), U_HARDWARE_BOOSTER_SCENARIO_USER_INTERACTION); } repowerd-2023.07/src/adapters/ubuntu_performance_booster.h000066400000000000000000000023231446034100200237130ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/performance_booster.h" #include #include namespace repowerd { class Log; class UbuntuPerformanceBooster : public PerformanceBooster { public: UbuntuPerformanceBooster(std::shared_ptr const& log); ~UbuntuPerformanceBooster(); void enable_interactive_mode() override; void disable_interactive_mode() override; private: std::shared_ptr const log; std::unique_ptr booster; }; } repowerd-2023.07/src/adapters/ubuntu_proximity_sensor.cpp000066400000000000000000000160201446034100200236440ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "ubuntu_proximity_sensor.h" #include "device_quirks.h" #include "event_loop_handler_registration.h" #include "src/core/log.h" #include #include namespace { char const* const log_tag = "UbuntuProximitySensor"; auto const null_handler = [](repowerd::ProximityState){}; char const* proximity_state_to_cstr(repowerd::ProximityState state) { return state == repowerd::ProximityState::far ? "far" : "near"; } } repowerd::UbuntuProximitySensor::UbuntuProximitySensor( std::shared_ptr const& log, DeviceQuirks const& device_quirks) : log{log}, sensor{ua_sensors_proximity_new()}, event_loop{"Proximity"}, handler{null_handler}, synthetic_event_seqno{1}, synthetic_event_delay{device_quirks.synthetic_initial_proximity_event_delay()}, synthetic_event_state{ device_quirks.synthetic_initial_proximity_event_type() == DeviceQuirks::ProximityEventType::far ? ProximityState::far : ProximityState::near}, is_state_valid{false}, state{ProximityState::far} { if (!sensor) throw std::runtime_error("Failed to allocate proximity sensor"); ua_sensors_proximity_set_reading_cb(sensor, static_sensor_reading_callback, this); } repowerd::HandlerRegistration repowerd::UbuntuProximitySensor::register_proximity_handler( ProximityHandler const& handler) { return EventLoopHandlerRegistration{ event_loop, [this, &handler]{ this->handler = handler; }, [this]{ this->handler = null_handler; }}; } repowerd::ProximityState repowerd::UbuntuProximitySensor::proximity_state() { log->logDebug(log_tag, "proximity_state()"); event_loop.enqueue( [this] { enable_proximity_events_unqueued(EnablementMode::without_handler); }).get(); auto const valid_state = wait_for_valid_state(); event_loop.enqueue( [this] { disable_proximity_events_unqueued(EnablementMode::without_handler); }); log->logDebug(log_tag, "proximity_state() => %s", proximity_state_to_cstr(valid_state)); return valid_state; } void repowerd::UbuntuProximitySensor::enable_proximity_events() { log->logDebug(log_tag, "enable_proximity_events()"); event_loop.enqueue( [this] { enable_proximity_events_unqueued(EnablementMode::with_handler); }).get(); } void repowerd::UbuntuProximitySensor::disable_proximity_events() { log->logDebug(log_tag, "disable_proximity_events()"); event_loop.enqueue( [this] { disable_proximity_events_unqueued(EnablementMode::with_handler); }).get(); } void repowerd::UbuntuProximitySensor::emit_proximity_event( repowerd::ProximityState state) { event_loop.enqueue([this, state] { handle_proximity_event(state); }).get(); } void repowerd::UbuntuProximitySensor::static_sensor_reading_callback( UASProximityEvent* event, void* context) { auto const ups = static_cast(context); auto const distance = uas_proximity_event_get_distance(event); auto const state = (distance == U_PROXIMITY_NEAR) ? ProximityState::near : ProximityState::far; ups->event_loop.enqueue([ups, state] { ups->handle_proximity_event(state); }); } void repowerd::UbuntuProximitySensor::handle_proximity_event(ProximityState new_state) { if (!is_enabled()) { log->logDebug(log_tag, "handle_proximity_event(%s): ignoring event, sensor is disabled", proximity_state_to_cstr(new_state)); return; } log->logDebug(log_tag, "handle_proximity_event(%s)", proximity_state_to_cstr(new_state)); invalidate_synthetic_initial_event(); { std::lock_guard lock{state_mutex}; state = new_state; is_state_valid = true; state_cv.notify_all(); } if (should_invoke_handler()) handler(state); } void repowerd::UbuntuProximitySensor::enable_proximity_events_unqueued( EnablementMode mode) { if (!is_enabled()) { ua_sensors_proximity_enable(sensor); schedule_synthetic_initial_event(); } enablements.push_back(mode); } void repowerd::UbuntuProximitySensor::disable_proximity_events_unqueued( EnablementMode mode) { if (is_enabled()) { auto const iter = std::find( enablements.begin(), enablements.end(), mode); if (iter != enablements.end()) enablements.erase(iter); if (!is_enabled()) { ua_sensors_proximity_disable(sensor); std::lock_guard lock{state_mutex}; is_state_valid = false; } } } repowerd::ProximityState repowerd::UbuntuProximitySensor::wait_for_valid_state() { std::unique_lock lock{state_mutex}; state_cv.wait( lock, [this] { return is_state_valid; }); return state; } void repowerd::UbuntuProximitySensor::schedule_synthetic_initial_event() { if (synthetic_event_delay.count() < 0 || synthetic_event_delay == std::chrono::milliseconds::max()) { return; } log->logDebug(log_tag, "schedule_synthetic_initial_event(), state=%s, delay_ms=%d", proximity_state_to_cstr(synthetic_event_state), static_cast(synthetic_event_delay.count())); // Some proximity sensors occasionally don't send an initial event when // enabled. Work around this by sending a synthetic initial event if no // events have been emitted "soon" after enabling the sensor. event_loop.schedule_in(synthetic_event_delay, [this, expected_seqno = synthetic_event_seqno] { if (synthetic_event_seqno == expected_seqno) { log->logDebug(log_tag, "emitting synthetic initial event %s", proximity_state_to_cstr(synthetic_event_state)); handle_proximity_event(synthetic_event_state); } }); } void repowerd::UbuntuProximitySensor::invalidate_synthetic_initial_event() { ++synthetic_event_seqno; } bool repowerd::UbuntuProximitySensor::is_enabled() { return !enablements.empty(); } bool repowerd::UbuntuProximitySensor::should_invoke_handler() { for (auto const& e : enablements) if (e == EnablementMode::with_handler) return true; return false; } repowerd-2023.07/src/adapters/ubuntu_proximity_sensor.h000066400000000000000000000045661446034100200233250ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/proximity_sensor.h" #include "event_loop.h" #include #include #include #include #include namespace repowerd { class DeviceQuirks; class Log; class UbuntuProximitySensor : public ProximitySensor { public: UbuntuProximitySensor( std::shared_ptr const& log, DeviceQuirks const& device_quirks); HandlerRegistration register_proximity_handler( ProximityHandler const& handler) override; ProximityState proximity_state() override; void enable_proximity_events() override; void disable_proximity_events() override; void emit_proximity_event(ProximityState state); private: enum class EnablementMode{with_handler, without_handler}; static void static_sensor_reading_callback(UASProximityEvent* event, void* context); void handle_proximity_event(ProximityState state); void enable_proximity_events_unqueued(EnablementMode mode); void disable_proximity_events_unqueued(EnablementMode mode); ProximityState wait_for_valid_state(); void schedule_synthetic_initial_event(); void invalidate_synthetic_initial_event(); bool is_enabled(); bool should_invoke_handler(); std::shared_ptr const log; UASensorsProximity* const sensor; EventLoop event_loop; std::vector enablements; ProximityHandler handler; int synthetic_event_seqno; std::chrono::milliseconds const synthetic_event_delay; ProximityState const synthetic_event_state; std::mutex state_mutex; std::condition_variable state_cv; bool is_state_valid; ProximityState state; }; } repowerd-2023.07/src/adapters/unique_random_pool.h000066400000000000000000000041341446034100200221540ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include #include #include #include #include namespace repowerd { template class UniqueRandomPool { public: UniqueRandomPool() : UniqueRandomPool{0} {} UniqueRandomPool(T min_value) : uniform_dist{min_value} {} T generate() { std::lock_guard lock{mutex}; uintmax_t const num_generated = generated.size(); // This doesn't work properly at the max limit when // sizeof(T) == sizeof(uintmax_t), but for such large types we // are not going to reach the max limit anyway. if (num_generated > 0 && num_generated - 1 == std::numeric_limits::max()) { throw std::runtime_error("UniqueRandomPool exhausted"); } T value; do { value = uniform_dist(random_dev); } while (generated.find(value) != generated.end()); generated.insert(value); return value; } void remove(T value) { std::lock_guard lock{mutex}; generated.erase(value); } size_t size() { std::lock_guard lock{mutex}; return generated.size(); } private: std::random_device random_dev; std::uniform_int_distribution uniform_dist; std::mutex mutex; std::unordered_set generated; }; } repowerd-2023.07/src/adapters/unity_screen_power_state_change_reason.h000066400000000000000000000016431446034100200262560ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { enum class UnityScreenPowerStateChangeReason { unknown = 0, inactivity = 1, power_key = 2, proximity = 3, notification = 4, snap_decision = 5, call_done = 6 }; } repowerd-2023.07/src/adapters/unity_screen_service.cpp000066400000000000000000001031271446034100200230410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "unity_screen_service.h" #include "unity_screen_power_state_change_reason.h" #include "brightness_notification.h" #include "event_loop_handler_registration.h" #include "scoped_g_error.h" #include "temporary_suspend_inhibition.h" #include "wakeup_service.h" #include "src/core/double_tap_to_wake.h" #include "src/core/infinite_timeout.h" #include "src/core/log.h" #include namespace { char const* const log_tag = "UnityScreenService"; auto const null_arg_handler = [](auto){}; auto const null_arg2_handler = [](auto,auto){}; int32_t reason_to_dbus_param(repowerd::DisplayPowerChangeReason reason) { repowerd::UnityScreenPowerStateChangeReason unity_screen_reason{ repowerd::UnityScreenPowerStateChangeReason::unknown}; switch (reason) { case repowerd::DisplayPowerChangeReason::power_button: unity_screen_reason = repowerd::UnityScreenPowerStateChangeReason::power_key; break; case repowerd::DisplayPowerChangeReason::activity: unity_screen_reason = repowerd::UnityScreenPowerStateChangeReason::inactivity; break; case repowerd::DisplayPowerChangeReason::proximity: unity_screen_reason = repowerd::UnityScreenPowerStateChangeReason::proximity; break; case repowerd::DisplayPowerChangeReason::notification: unity_screen_reason = repowerd::UnityScreenPowerStateChangeReason::notification; break; case repowerd::DisplayPowerChangeReason::call: unity_screen_reason = repowerd::UnityScreenPowerStateChangeReason::unknown; break; case repowerd::DisplayPowerChangeReason::call_done: unity_screen_reason = repowerd::UnityScreenPowerStateChangeReason::call_done; break; default: break; }; return static_cast(unity_screen_reason); } char const* const dbus_screen_interface = "com.canonical.Unity.Screen"; char const* const dbus_screen_path = "/com/canonical/Unity/Screen"; char const* const dbus_screen_service_name = "com.canonical.Unity.Screen"; char const* const unity_screen_service_introspection = R"( )"; char const* const dbus_repowerd_interface = "com.lomiri.Repowerd"; char const* const dbus_repowerd_path = "/com/lomiri/Repowerd"; char const* const dbus_repowerd_service_name = "com.lomiri.Repowerd"; char const* const dbus_repowerd_service_introspection = R"( )"; std::string notification_id(std::string const& sender, size_t index) { return sender + "-" + std::to_string(index); } } repowerd::UnityScreenService::UnityScreenService( std::shared_ptr const& wakeup_service, std::shared_ptr const& brightness_notification, std::shared_ptr const& log, std::shared_ptr const& temporary_suspend_inhibition, std::shared_ptr const& double_tap_to_wake_control, DeviceConfig const& device_config, std::string const& dbus_bus_address) : wakeup_service{wakeup_service}, brightness_notification{brightness_notification}, temporary_suspend_inhibition{temporary_suspend_inhibition}, log{log}, double_tap_to_wake_control{double_tap_to_wake_control}, dbus_connection{dbus_bus_address}, dbus_event_loop{"DBusService"}, disable_inactivity_timeout_handler{null_arg2_handler}, enable_inactivity_timeout_handler{null_arg2_handler}, set_inactivity_timeout_handler{null_arg2_handler}, disable_autobrightness_handler{null_arg_handler}, enable_autobrightness_handler{null_arg_handler}, set_normal_brightness_value_handler{null_arg2_handler}, notification_handler{null_arg2_handler}, notification_done_handler{null_arg2_handler}, allow_suspend_handler{null_arg2_handler}, disallow_suspend_handler{null_arg2_handler}, started{false}, next_keep_display_on_id{1}, next_request_sys_state_id{1}, brightness_params(BrightnessParams::from_device_config(device_config)) { } void repowerd::UnityScreenService::start_processing() { if (started) return; unity_screen_handler_registration = dbus_event_loop.register_object_handler( dbus_connection, dbus_screen_path, unity_screen_service_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); name_owner_changed_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameOwnerChanged", "/org/freedesktop/DBus", [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); powerd_handler_registration = dbus_event_loop.register_object_handler( dbus_connection, dbus_repowerd_path, dbus_repowerd_service_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); wakeup_handler_registration = wakeup_service->register_wakeup_handler( [this] (std::string const& cookie) { temporary_suspend_inhibition->inhibit_suspend_for( std::chrono::seconds{3}, "Wakeup_" + cookie); dbus_event_loop.enqueue([this] { dbus_emit_Wakeup(); }); }); brightness_handler_registration = brightness_notification->register_brightness_handler( [this] (double brightness) { dbus_event_loop.enqueue([this,brightness] { dbus_emit_brightness(brightness); }); }); dbus_connection.request_name(dbus_screen_service_name); dbus_connection.request_name(dbus_repowerd_service_name); started = true; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_enable_inactivity_timeout_handler( EnableInactivityTimeoutHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { enable_inactivity_timeout_handler = handler; }, [this] { enable_inactivity_timeout_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_disable_inactivity_timeout_handler( DisableInactivityTimeoutHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { disable_inactivity_timeout_handler = handler; }, [this] { disable_inactivity_timeout_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_set_inactivity_timeout_handler( SetInactivityTimeoutHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { set_inactivity_timeout_handler = handler; }, [this] { set_inactivity_timeout_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_disable_autobrightness_handler( DisableAutobrightnessHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { disable_autobrightness_handler = handler; }, [this] { disable_autobrightness_handler = null_arg_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_enable_autobrightness_handler( EnableAutobrightnessHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { enable_autobrightness_handler = handler; }, [this] { enable_autobrightness_handler = null_arg_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_set_normal_brightness_value_handler( SetNormalBrightnessValueHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { set_normal_brightness_value_handler = handler; }, [this] { set_normal_brightness_value_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_notification_handler( NotificationHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { notification_handler = handler; }, [this] { notification_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_notification_done_handler( NotificationDoneHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { notification_done_handler = handler; }, [this] { notification_done_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_allow_suspend_handler( AllowSuspendHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { allow_suspend_handler = handler; }, [this] { allow_suspend_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration repowerd::UnityScreenService::register_disallow_suspend_handler( DisallowSuspendHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { disallow_suspend_handler = handler; }, [this] { disallow_suspend_handler = null_arg2_handler; }}; } void repowerd::UnityScreenService::notify_display_power_on( DisplayPowerChangeReason reason) { int32_t const power_state_on = 1; int32_t const reason_param = reason_to_dbus_param(reason); dbus_emit_DisplayPowerStateChange(power_state_on, reason_param); } void repowerd::UnityScreenService::notify_display_power_off( DisplayPowerChangeReason reason) { int32_t const power_state_off = 0; int32_t const reason_param = reason_to_dbus_param(reason); dbus_emit_DisplayPowerStateChange(power_state_off, reason_param); } void repowerd::UnityScreenService::dbus_method_call( GDBusConnection* /*connection*/, gchar const* sender_cstr, gchar const* /*object_path_cstr*/, gchar const* /*interface_name_cstr*/, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation) { std::string const sender{sender_cstr ? sender_cstr : ""}; std::string const method_name{method_name_cstr ? method_name_cstr : ""}; auto const pid = dbus_get_invocation_sender_pid(invocation); if (method_name == "keepDisplayOn") { auto const id = dbus_keepDisplayOn(sender, pid); g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", id)); } else if (method_name == "removeDisplayOnRequest") { int32_t id{-1}; g_variant_get(parameters, "(i)", &id); dbus_removeDisplayOnRequest(sender, id, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "setUserBrightness") { int32_t brightness{0}; g_variant_get(parameters, "(i)", &brightness); dbus_setUserBrightness(brightness, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "setInactivityTimeouts") { int32_t poweroff_timeout{-1}; int32_t dimmer_timeout{-1}; g_variant_get(parameters, "(ii)", &poweroff_timeout, &dimmer_timeout); dbus_setInactivityTimeouts(poweroff_timeout, dimmer_timeout, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "userAutobrightnessEnable") { gboolean enable{FALSE}; g_variant_get(parameters, "(b)", &enable); dbus_userAutobrightnessEnable(enable == TRUE, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "setScreenPowerMode") { char const* mode{""}; int32_t reason{-1}; g_variant_get(parameters, "(&si)", &mode, &reason); auto const result = dbus_setScreenPowerMode(sender, mode, reason, pid); g_dbus_method_invocation_return_value( invocation, g_variant_new("(b)", result ? TRUE : FALSE)); } else if (method_name == "requestSysState") { char const* name{""}; int32_t state{-1}; g_variant_get(parameters, "(&si)", &name, &state); try { auto const cookie = dbus_requestSysState(sender, name, state, pid); g_dbus_method_invocation_return_value( invocation, g_variant_new("(s)", cookie.c_str())); } catch (std::exception const& e) { g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, e.what()); } } else if (method_name == "clearSysState") { char const* cookie{""}; g_variant_get(parameters, "(&s)", &cookie); dbus_clearSysState(sender, cookie, pid); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "listSysRequests") { g_dbus_method_invocation_return_value(invocation, dbus_listSysRequests()); } else if (method_name == "requestWakeup") { char const* name{""}; uint64_t time{0}; g_variant_get(parameters, "(&st)", &name, &time); auto const cookie = dbus_requestWakeup(sender, name, time); g_dbus_method_invocation_return_value( invocation, g_variant_new("(s)", cookie.c_str())); } else if (method_name == "clearWakeup") { char const* cookie{""}; g_variant_get(parameters, "(&s)", &cookie); dbus_clearWakeup(sender, cookie); g_dbus_method_invocation_return_value(invocation, NULL); } else if (method_name == "getBrightnessParams") { auto params = dbus_getBrightnessParams(); g_dbus_method_invocation_return_value( invocation, g_variant_new("((iiiib))", params.dim_value, params.min_value, params.max_value, params.default_value, params.autobrightness_supported)); } else if (method_name == "getDoubleTapToWakeEnabled") { auto enabled = dbus_getDoubleTapToWakeEnabled(); g_dbus_method_invocation_return_value( invocation, g_variant_new("(b)", enabled)); } else if (method_name == "getDoubleTapToWakeSupported") { auto supported = dbus_getDoubleTapToWakeSupported(); g_dbus_method_invocation_return_value( invocation, g_variant_new("(b)", supported)); } else if (method_name == "setDoubleTapToWakeEnabled") { gboolean enable{FALSE}; g_variant_get(parameters, "(b)", &enable); dbus_setDoubleTapToWakeEnabled(enable == TRUE); g_dbus_method_invocation_return_value(invocation, NULL); } else { dbus_unknown_method(sender, method_name); g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); } } void repowerd::UnityScreenService::dbus_signal( GDBusConnection* /*connection*/, gchar const* sender_cstr, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* signal_name_cstr, GVariant* parameters) { std::string const sender{sender_cstr ? sender_cstr : ""}; std::string const object_path{object_path_cstr ? object_path_cstr : ""}; std::string const interface_name{interface_name_cstr ? interface_name_cstr : ""}; std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; if (sender == "org.freedesktop.DBus" && object_path == "/org/freedesktop/DBus" && interface_name == "org.freedesktop.DBus" && signal_name == "NameOwnerChanged") { char const* name = ""; char const* old_owner = ""; char const* new_owner = ""; g_variant_get(parameters, "(&s&s&s)", &name, &old_owner, &new_owner); dbus_NameOwnerChanged(name, old_owner, new_owner); } } int32_t repowerd::UnityScreenService::dbus_keepDisplayOn( std::string const& sender, pid_t pid) { log->logDebug(log_tag, "dbus_keepDisplayOn(%s)", sender.c_str()); auto const id = next_keep_display_on_id++; keep_display_on_data_t d = {id, pid}; keep_display_on_ids.emplace(sender, d); disable_inactivity_timeout_handler(std::to_string(id), pid); log->logDebug(log_tag, "dbus_keepDisplayOn(%s) => %d", sender.c_str(), id); return id; } void repowerd::UnityScreenService::dbus_removeDisplayOnRequest( std::string const& sender, int32_t id, pid_t pid) { log->logDebug(log_tag, "dbus_removeDisplayOnRequest(%s,%d)", sender.c_str(), id); bool id_removed{false}; auto range = keep_display_on_ids.equal_range(sender); for (auto iter = range.first; iter != range.second; ++iter) { if (iter->second.id == id) { keep_display_on_ids.erase(iter); id_removed = true; break; } } if (id_removed) enable_inactivity_timeout_handler(std::to_string(id), pid); } void repowerd::UnityScreenService::dbus_NameOwnerChanged( std::string const& name, std::string const& old_owner, std::string const& new_owner) { if (keep_display_on_ids.find(name) != keep_display_on_ids.end() || request_sys_state_ids.find(name) != request_sys_state_ids.end() || active_notifications.find(name) != active_notifications.end()) { log->logDebug(log_tag, "dbus_NameOwnerChanged(%s,%s,%s)", name.c_str(), old_owner.c_str(), new_owner.c_str()); } if (new_owner.empty() && old_owner == name) { auto const kdo_range = keep_display_on_ids.equal_range(name); for (auto iter = kdo_range.first; iter != kdo_range.second; ++iter) enable_inactivity_timeout_handler(std::to_string(iter->second.id), 0); keep_display_on_ids.erase(name); auto rss_range = request_sys_state_ids.equal_range(name); for (auto iter = rss_range.first; iter != rss_range.second; ++iter) allow_suspend_handler(std::to_string(iter->second.id), 0); request_sys_state_ids.erase(name); auto const num_notifications_removed = active_notifications.erase(name); for (auto i = 0u; i < num_notifications_removed; ++i) notification_done_handler(notification_id(name, i), 0); } } void repowerd::UnityScreenService::dbus_userAutobrightnessEnable( bool enable, pid_t pid) { log->logDebug(log_tag, "dbus_userAutobrightnessEnable(%s)", enable ? "enable" : "disable"); if (enable) enable_autobrightness_handler(pid); else disable_autobrightness_handler(pid); } void repowerd::UnityScreenService::dbus_setUserBrightness( int32_t brightness, pid_t pid) { log->logDebug(log_tag, "dbus_setUserBrightness(%d)", brightness); set_normal_brightness_value_handler( brightness/static_cast(brightness_params.max_value), pid); } void repowerd::UnityScreenService::dbus_setInactivityTimeouts( int32_t poweroff_timeout, int32_t dimmer_timeout, pid_t pid) { log->logDebug(log_tag, "dbus_setInactivityTimeouts(%d,%d)", poweroff_timeout, dimmer_timeout); if (poweroff_timeout < 0) return; auto const timeout = poweroff_timeout == 0 ? repowerd::infinite_timeout : std::chrono::seconds{poweroff_timeout}; set_inactivity_timeout_handler(timeout, pid); } bool repowerd::UnityScreenService::dbus_setScreenPowerMode( std::string const& sender, std::string const& mode, int32_t reason, pid_t pid) { log->logDebug(log_tag, "dbus_setScreenPowerMode(%s,%s,%d)", sender.c_str(), mode.c_str(), reason); if (reason == static_cast(UnityScreenPowerStateChangeReason::notification) || reason == static_cast(UnityScreenPowerStateChangeReason::snap_decision)) { if (mode == "on") { auto const id = notification_id(sender, active_notifications.count(sender)); active_notification_t d = {pid, reason}; active_notifications.emplace(sender, d); notification_handler(id, pid); } else if (mode == "off") { auto const iter = active_notifications.find(sender); if (iter != active_notifications.end()) { active_notifications.erase(iter); auto const id = notification_id(sender, active_notifications.count(sender)); notification_done_handler(id, pid); } } return true; } return false; } void repowerd::UnityScreenService::dbus_emit_DisplayPowerStateChange( int32_t power_state, int32_t reason) { log->logDebug(log_tag, "dbus_emit_DisplayPowerStateChange(%d,%d)", power_state, reason); g_dbus_connection_emit_signal( dbus_connection, nullptr, dbus_screen_path, dbus_screen_interface, "DisplayPowerStateChange", g_variant_new("(ii)", power_state, reason), nullptr); } std::string repowerd::UnityScreenService::dbus_requestSysState( std::string const& sender, std::string const& name, int32_t state, pid_t pid) { log->logDebug(log_tag, "dbus_requestSysState(%s,%s,%d)", sender.c_str(), name.c_str(), state); int32_t const active_state{1}; if (state != active_state) throw std::runtime_error{"Invalid state"}; auto const id = next_request_sys_state_id++; request_sys_state_data_t d = {id, pid, name}; request_sys_state_ids.emplace(sender, d); disallow_suspend_handler(std::to_string(id), pid); log->logDebug(log_tag, "dbus_requestSysState(%s,%s,%d) => %d", sender.c_str(), name.c_str(), state, id); return std::to_string(id); } void repowerd::UnityScreenService::dbus_clearSysState( std::string const& sender, std::string const& cookie, pid_t pid) { log->logDebug(log_tag, "dbus_clearSysState(%s,%s)", sender.c_str(), cookie.c_str()); bool id_removed{false}; int32_t id = 0; try { id = std::stoi(cookie); } catch(...) {} auto range = request_sys_state_ids.equal_range(sender); for (auto iter = range.first; iter != range.second; ++iter) { if (iter->second.id == id) { request_sys_state_ids.erase(iter); id_removed = true; break; } } if (id_removed) allow_suspend_handler(std::to_string(id), pid); } GVariant *repowerd::UnityScreenService::dbus_listSysRequests() { GVariant *ret_tuple[1]; GVariant *dict_entries[3]; GVariant **array_entries = new GVariant*[request_sys_state_ids.size()]; { auto itr = request_sys_state_ids.begin(); int i = 0; for(; itr != request_sys_state_ids.end(); itr++, i++){ GVariant *tuple[4]; tuple[0] = g_variant_new_string(itr->first.c_str()); tuple[1] = g_variant_new_int32(itr->second.id); tuple[2] = g_variant_new_uint64(itr->second.pid); tuple[3] = g_variant_new_string(itr->second.name.c_str()); array_entries[i] = g_variant_new_tuple(tuple, sizeof(tuple) / sizeof(GVariant *)); } auto gvt = g_variant_type_new("(sits)"); auto request_sys_state_array = g_variant_new_array(gvt, array_entries, request_sys_state_ids.size()); g_variant_type_free(gvt); dict_entries[0] = g_variant_new_dict_entry(g_variant_new_string("request_sys_state"), g_variant_new_variant(request_sys_state_array)); } delete [] array_entries; array_entries = new GVariant*[keep_display_on_ids.size()]; { auto itr = keep_display_on_ids.begin(); int i = 0; for(; itr != keep_display_on_ids.end(); itr++, i++){ GVariant *tuple[3]; tuple[0] = g_variant_new_string(itr->first.c_str()); tuple[1] = g_variant_new_int32(itr->second.id); tuple[2] = g_variant_new_uint64(itr->second.pid); array_entries[i] = g_variant_new_tuple(tuple, sizeof(tuple) / sizeof(GVariant *)); } auto gvt = g_variant_type_new("(sit)"); auto keep_display_on_array = g_variant_new_array(gvt, array_entries, keep_display_on_ids.size()); g_variant_type_free(gvt); dict_entries[1] = g_variant_new_dict_entry(g_variant_new_string("keep_display_on"), g_variant_new_variant(keep_display_on_array)); } delete [] array_entries; array_entries = new GVariant*[active_notifications.size()]; { auto itr = active_notifications.begin(); int i = 0; for(; itr != active_notifications.end(); itr++, i++){ GVariant *tuple[3]; tuple[0] = g_variant_new_string(itr->first.c_str()); tuple[1] = g_variant_new_uint64(itr->second.pid); tuple[2] = g_variant_new_int32(itr->second.reason); array_entries[i] = g_variant_new_tuple(tuple, sizeof(tuple) / sizeof(GVariant *)); } auto gvt = g_variant_type_new("(sti)"); auto active_notifications_array = g_variant_new_array(gvt, array_entries, active_notifications.size()); g_variant_type_free(gvt); dict_entries[2] = g_variant_new_dict_entry(g_variant_new_string("active_notifications"), g_variant_new_variant(active_notifications_array)); } delete [] array_entries; auto gvt = g_variant_type_new("{sv}"); ret_tuple[0] = g_variant_new_array(gvt, dict_entries, sizeof(dict_entries) / sizeof(GVariant *)); g_variant_type_free(gvt); return g_variant_new_tuple(ret_tuple, 1); } std::string repowerd::UnityScreenService::dbus_requestWakeup( std::string const& sender, std::string const& name, uint64_t time) { log->logDebug(log_tag, "dbus_requestWakeup(%s,%s,%ju)", sender.c_str(), name.c_str(), static_cast(time)); auto const cookie = wakeup_service->schedule_wakeup_at(std::chrono::system_clock::from_time_t(time)); log->logDebug(log_tag, "dbus_requestWakeup(%s,%s,%ju) => %s", sender.c_str(), name.c_str(), static_cast(time), cookie.c_str()); return cookie; } void repowerd::UnityScreenService::dbus_clearWakeup( std::string const& sender, std::string const& cookie) { log->logDebug(log_tag, "dbus_clearWakeup(%s,%s)", sender.c_str(), cookie.c_str()); wakeup_service->cancel_wakeup(cookie); } repowerd::BrightnessParams repowerd::UnityScreenService::dbus_getBrightnessParams() { log->logDebug(log_tag, "dbus_getBrightnessParams() => (%d,%d,%d,%d,%s)", brightness_params.dim_value, brightness_params.min_value, brightness_params.max_value, brightness_params.default_value, brightness_params.autobrightness_supported ? "true" : "false"); return brightness_params; } void repowerd::UnityScreenService::dbus_emit_Wakeup() { log->logDebug(log_tag, "dbus_emit_Wakeup()"); g_dbus_connection_emit_signal( dbus_connection, nullptr, dbus_repowerd_path, dbus_repowerd_interface, "Wakeup", nullptr, nullptr); } void repowerd::UnityScreenService::dbus_emit_brightness(double brightness) { int32_t const brightness_abs = round(brightness * brightness_params.max_value); log->logDebug(log_tag, "dbus_emit_brightness(%f), brightness_value=%d", brightness, brightness_abs); g_dbus_connection_emit_signal( dbus_connection, nullptr, dbus_repowerd_path, "org.freedesktop.DBus.Properties", "PropertiesChanged", g_variant_new_parsed( "(@s %s, @a{sv} {'brightness': <%i>}, @as [])", dbus_repowerd_interface, brightness_abs), nullptr); } bool repowerd::UnityScreenService::dbus_getDoubleTapToWakeEnabled() { log->logDebug(log_tag, "dbus_getDoubleTapToWakeEnabled()"); return double_tap_to_wake_control->is_enabled(); } bool repowerd::UnityScreenService::dbus_getDoubleTapToWakeSupported() { log->logDebug(log_tag, "dbus_getDoubleTapToWakeSupported()"); return double_tap_to_wake_control->is_supported(); } void repowerd::UnityScreenService::dbus_setDoubleTapToWakeEnabled(bool enable) { log->logDebug(log_tag, "dbus_setDoubleTapToWakeEnabled(%s)", enable ? "enable" : "disable"); if (enable) double_tap_to_wake_control->enable(); else double_tap_to_wake_control->disable(); } void repowerd::UnityScreenService::dbus_unknown_method( std::string const& sender, std::string const& name) { log->logWarning(log_tag, "dbus_unknown_method(%s,%s)", sender.c_str(), name.c_str()); } pid_t repowerd::UnityScreenService::dbus_get_invocation_sender_pid( GDBusMethodInvocation* invocation) { int constexpr timeout = 1000; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const sender = g_dbus_method_invocation_get_sender(invocation); auto const result = g_dbus_connection_call_sync( dbus_connection, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetConnectionUnixProcessID", g_variant_new("(s)", sender), G_VARIANT_TYPE("(u)"), G_DBUS_CALL_FLAGS_NONE, timeout, null_cancellable, error); if (!result) { log->logWarning(log_tag, "failed to get pid of '%s': %s", sender, error.message_str().c_str()); return -1; } guint pid; g_variant_get(result, "(u)", &pid); g_variant_unref(result); return pid; } repowerd-2023.07/src/adapters/unity_screen_service.h000066400000000000000000000170621446034100200225100ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/client_requests.h" #include "src/core/display_power_event_sink.h" #include "src/core/notification_service.h" #include "brightness_params.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include #include #include #include #include #include namespace repowerd { class BrightnessNotification; class DeviceConfig; class DoubleTapToWake; class Log; class TemporarySuspendInhibition; class WakeupService; class UnityScreenService : public ClientRequests, public DisplayPowerEventSink, public NotificationService { public: UnityScreenService( std::shared_ptr const& wakeup_service, std::shared_ptr const& brightness_notification, std::shared_ptr const& log, std::shared_ptr const& temporary_suspend_inhibition, std::shared_ptr const& double_tap_to_wake_control, DeviceConfig const& device_config, std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_disable_inactivity_timeout_handler( DisableInactivityTimeoutHandler const& handler) override; HandlerRegistration register_enable_inactivity_timeout_handler( EnableInactivityTimeoutHandler const& handler) override; HandlerRegistration register_set_inactivity_timeout_handler( SetInactivityTimeoutHandler const& handler) override; HandlerRegistration register_disable_autobrightness_handler( DisableAutobrightnessHandler const& handler) override; HandlerRegistration register_enable_autobrightness_handler( EnableAutobrightnessHandler const& handler) override; HandlerRegistration register_set_normal_brightness_value_handler( SetNormalBrightnessValueHandler const& handler) override; HandlerRegistration register_notification_handler( NotificationHandler const& handler) override; HandlerRegistration register_notification_done_handler( NotificationDoneHandler const& handler) override; HandlerRegistration register_allow_suspend_handler( DisallowSuspendHandler const& handler) override; HandlerRegistration register_disallow_suspend_handler( AllowSuspendHandler const& handler) override; void notify_display_power_on(DisplayPowerChangeReason reason) override; void notify_display_power_off(DisplayPowerChangeReason reason) override; private: void dbus_method_call( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation); void dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); int32_t dbus_keepDisplayOn(std::string const& sender, pid_t pid); void dbus_removeDisplayOnRequest(std::string const& sender, int32_t id, pid_t pid); void dbus_setUserBrightness(int32_t brightness, pid_t pid); void dbus_setInactivityTimeouts(int32_t poweroff_timeout, int32_t dimmer_timeout, pid_t pid); void dbus_userAutobrightnessEnable(bool enable, pid_t pid); void dbus_NameOwnerChanged( std::string const& name, std::string const& old_owner, std::string const& new_owner); bool dbus_setScreenPowerMode( std::string const& sender, std::string const& mode, int32_t reason, pid_t pid); void dbus_emit_DisplayPowerStateChange(int32_t power_state, int32_t reason); std::string dbus_requestSysState( std::string const& sender, std::string const& name, int32_t state, pid_t pid); void dbus_clearSysState( std::string const& sender, std::string const& cookie, pid_t pid); GVariant *dbus_listSysRequests(); std::string dbus_requestWakeup( std::string const& sender, std::string const& name, uint64_t time); void dbus_clearWakeup(std::string const& sender, std::string const& cookie); BrightnessParams dbus_getBrightnessParams(); void dbus_emit_Wakeup(); void dbus_emit_brightness(double brightness); bool dbus_getDoubleTapToWakeEnabled(); void dbus_setDoubleTapToWakeEnabled(bool enable); bool dbus_getDoubleTapToWakeSupported(); void dbus_unknown_method(std::string const& sender, std::string const& name); pid_t dbus_get_invocation_sender_pid(GDBusMethodInvocation* invocation); std::shared_ptr const wakeup_service; std::shared_ptr const brightness_notification; std::shared_ptr const temporary_suspend_inhibition; std::shared_ptr const log; std::shared_ptr const double_tap_to_wake_control; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; DisableInactivityTimeoutHandler disable_inactivity_timeout_handler; EnableInactivityTimeoutHandler enable_inactivity_timeout_handler; SetInactivityTimeoutHandler set_inactivity_timeout_handler; DisableAutobrightnessHandler disable_autobrightness_handler; EnableAutobrightnessHandler enable_autobrightness_handler; SetNormalBrightnessValueHandler set_normal_brightness_value_handler; NotificationHandler notification_handler; NotificationDoneHandler notification_done_handler; AllowSuspendHandler allow_suspend_handler; DisallowSuspendHandler disallow_suspend_handler; bool started; typedef struct { const int32_t id; const pid_t pid; } keep_display_on_data_t; std::unordered_multimap keep_display_on_ids; int32_t next_keep_display_on_id; typedef struct { const pid_t pid; const int32_t reason; } active_notification_t; std::unordered_multimap active_notifications; typedef struct { const int32_t id; const pid_t pid; const std::string name; } request_sys_state_data_t; std::unordered_multimap request_sys_state_ids; int32_t next_request_sys_state_id; BrightnessParams brightness_params; // These need to be at the end, so that handlers are unregistered first on // destruction, to avoid accessing other members if an event arrives // on destruction. HandlerRegistration unity_screen_handler_registration; HandlerRegistration name_owner_changed_handler_registration; HandlerRegistration powerd_handler_registration; HandlerRegistration wakeup_handler_registration; HandlerRegistration brightness_handler_registration; }; } repowerd-2023.07/src/adapters/upower_power_source_and_lid.cpp000066400000000000000000000402521446034100200244000ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "upower_power_source_and_lid.h" #include "device_config.h" #include "event_loop_handler_registration.h" #include "scoped_g_error.h" #include "temporary_suspend_inhibition.h" #include "src/core/log.h" #include namespace { char const* const log_tag = "UPowerPowerSourceAndLid"; auto const null_handler = []{}; auto const null_arg_handler = [](auto){}; char const* const dbus_upower_name = "org.freedesktop.UPower"; char const* const dbus_upower_path = "/org/freedesktop/UPower"; char const* const dbus_upower_interface = "org.freedesktop.UPower"; char const* const display_device_path = "/org/freedesktop/UPower/devices/DisplayDevice"; enum class DeviceState { unknown = 0, charging, discharging, empty, fully_charged, pending_charge, pending_discharge }; enum class DeviceType { unknown = 0, line_power, battery, ups }; std::string device_type_to_str(uint32_t type) { if (type == static_cast(DeviceType::unknown)) return "unknown"; else if (type == static_cast(DeviceType::line_power)) return "line_power"; else if (type == static_cast(DeviceType::battery)) return "battery"; else if (type == static_cast(DeviceType::ups)) return "ups"; else return "unsupported(" + std::to_string(type) + ")"; } std::string device_state_to_str(uint32_t state) { if (state == static_cast(DeviceState::unknown)) return "unknown"; else if (state == static_cast(DeviceState::charging)) return "charging"; else if (state == static_cast(DeviceState::discharging)) return "discharging"; else if (state == static_cast(DeviceState::empty)) return "empty"; else if (state == static_cast(DeviceState::fully_charged)) return "fully_charged"; else if (state == static_cast(DeviceState::pending_charge)) return "pending_charge"; else if (state == static_cast(DeviceState::pending_discharge)) return "pending_discharge"; else return "unsupported(" + std::to_string(state) + ")"; } double get_critical_temperature(repowerd::DeviceConfig const& device_config) try { auto const ct_str = device_config.get("shutdownBatteryTemperature", "680"); return ((double)std::stoi(ct_str)) * 0.1; } catch (...) { return 68.0; } double constexpr critical_percentage{2.0}; double constexpr non_critical_percentage{3.0}; } repowerd::UPowerPowerSourceAndLid::UPowerPowerSourceAndLid( std::shared_ptr const& log, std::shared_ptr const& temporary_suspend_inhibition, DeviceConfig const& device_config, std::string const& dbus_bus_address) : log{log}, temporary_suspend_inhibition{temporary_suspend_inhibition}, critical_temperature{get_critical_temperature(device_config)}, dbus_connection{dbus_bus_address}, dbus_event_loop{"UPower"}, power_source_change_handler{null_handler}, power_source_critical_handler{null_handler}, lid_handler{null_arg_handler}, started{false}, highest_seen_percentage{0.0}, display_device{} { } void repowerd::UPowerPowerSourceAndLid::start_processing() { if (started) return; dbus_signal_handler_registration = dbus_event_loop.register_signal_handler( dbus_connection, dbus_upower_name, nullptr, nullptr, nullptr, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters) { handle_dbus_signal( connection, sender, object_path, interface_name, signal_name, parameters); }); dbus_event_loop.enqueue( [this] { add_display_device(); add_existing_batteries(); }).get(); started = true; } repowerd::HandlerRegistration repowerd::UPowerPowerSourceAndLid::register_power_source_change_handler( PowerSourceChangeHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->power_source_change_handler = handler; }, [this] { this->power_source_change_handler = null_handler; }}; } repowerd::HandlerRegistration repowerd::UPowerPowerSourceAndLid::register_power_source_critical_handler( PowerSourceCriticalHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->power_source_critical_handler = handler; }, [this] { this->power_source_critical_handler = null_handler; }}; } repowerd::HandlerRegistration repowerd::UPowerPowerSourceAndLid::register_lid_handler( LidHandler const& handler) { return EventLoopHandlerRegistration{ dbus_event_loop, [this, &handler] { this->lid_handler = handler; }, [this] { this->lid_handler = null_arg_handler; }}; } bool repowerd::UPowerPowerSourceAndLid::is_using_battery_power() { int constexpr timeout = 1000; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_upower_name, "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "Get", g_variant_new("(ss)", "org.freedesktop.UPower", "OnBattery"), G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, timeout, null_cancellable, error); if (!result) { log->logWarning(log_tag, "is_using_battery_power() failed, assuming true, more info: %s", error.message_str().c_str()); return true; } GVariant* on_battery; g_variant_get(result, "(v)", &on_battery); auto const ret = g_variant_get_boolean(on_battery); g_variant_unref(on_battery); g_variant_unref(result); log->logDebug(log_tag, "is_using_battery_power() => %s", ret ? "true" : "false"); return ret; } std::unordered_set repowerd::UPowerPowerSourceAndLid::tracked_batteries() { std::unordered_set ret_batteries; dbus_event_loop.enqueue( [this, &ret_batteries] { for (auto const& battery : batteries) ret_batteries.insert(battery.first); }).get(); return ret_batteries; } void repowerd::UPowerPowerSourceAndLid::handle_dbus_signal( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* object_path_cstr, gchar const* /*interface_name*/, gchar const* signal_name_cstr, GVariant* parameters) { std::string const object_path{object_path_cstr ? object_path_cstr : ""}; std::string const signal_name{signal_name_cstr ? signal_name_cstr : ""}; if (signal_name == "PropertiesChanged") { char const* properties_interface_cstr{""}; GVariantIter* properties_iter; g_variant_get(parameters, "(&sa{sv}as)", &properties_interface_cstr, &properties_iter, nullptr); std::string const properties_interface{properties_interface_cstr}; if (properties_interface == "org.freedesktop.UPower.Device") change_device(object_path, properties_iter); else if (properties_interface == "org.freedesktop.UPower") change_upower(properties_iter); g_variant_iter_free(properties_iter); } else if (signal_name == "DeviceAdded") { char const* device{""}; g_variant_get(parameters, "(&o)", &device); add_device_if_battery(device); } else if (signal_name == "DeviceRemoved") { char const* device{""}; g_variant_get(parameters, "(&o)", &device); remove_device(device); } } void repowerd::UPowerPowerSourceAndLid::add_display_device() { display_device = create_device(display_device_path); highest_seen_percentage = display_device.percentage; log_device("add_display_device", display_device); } void repowerd::UPowerPowerSourceAndLid::add_existing_batteries() { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; auto constexpr null_args = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_upower_name, dbus_upower_path, dbus_upower_interface, "EnumerateDevices", null_args, G_VARIANT_TYPE("(ao)"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "add_existing_batteries() failed to EnumerateDevices: %s", error.message_str().c_str()); return; } GVariantIter* result_devices; g_variant_get(result, "(ao)", &result_devices); char const* device{""}; while (g_variant_iter_next(result_devices, "&o", &device)) add_device_if_battery(device); g_variant_iter_free(result_devices); g_variant_unref(result); } void repowerd::UPowerPowerSourceAndLid::add_device_if_battery( std::string const& device_path) { auto const device = create_device(device_path); if (device.type == static_cast(DeviceType::battery)) { log_device("add_device_if_battery", device); batteries[device.path] = device; } } void repowerd::UPowerPowerSourceAndLid::remove_device(std::string const& device_path) { if (batteries.find(device_path) == batteries.end()) return; log->logDebug(log_tag, "remove_device(%s)", device_path.c_str()); batteries.erase(device_path); } void repowerd::UPowerPowerSourceAndLid::change_device( std::string const& device_path, GVariantIter* properties_iter) { bool const is_display_device = device_path == display_device_path; if (!is_display_device && batteries.find(device_path) == batteries.end()) return; auto& device = is_display_device ? display_device : batteries[device_path]; auto const old_info = device; update_device(device, properties_iter); auto new_info = device; log_device("change_device", new_info); bool critical{false}; bool change{false}; if (is_display_device) { if (old_info.is_present != new_info.is_present || old_info.type != new_info.type) { change = true; } if (new_info.is_present && old_info.state != new_info.state) { if (new_info.state == static_cast(DeviceState::discharging) || (old_info.state == static_cast(DeviceState::discharging) && (new_info.state == static_cast(DeviceState::charging) || new_info.state == static_cast(DeviceState::fully_charged) || new_info.state == static_cast(DeviceState::pending_charge)))) { change = true; } } if (new_info.is_present && old_info.percentage != new_info.percentage) { highest_seen_percentage = std::max(highest_seen_percentage, new_info.percentage); if (new_info.percentage <= critical_percentage && is_using_battery_power() && highest_seen_percentage >= non_critical_percentage) { log->logInfo(log_tag, "Battery energy percentage is at critical level %.1f%%\n", new_info.percentage); critical = true; } } } else { if (new_info.is_present && old_info.temperature != new_info.temperature) { if (new_info.temperature >= critical_temperature) { log->logInfo(log_tag, "Battery temperature is at critical level %.1f (limit is %.1f)\n", new_info.temperature, critical_temperature); critical = true; } } } if (critical || change) { temporary_suspend_inhibition->inhibit_suspend_for( std::chrono::seconds{2}, "UPowerPowerSource"); } if (critical) { highest_seen_percentage = 0.0; power_source_critical_handler(); } if (change) power_source_change_handler(); } void repowerd::UPowerPowerSourceAndLid::change_upower( GVariantIter* properties_iter) { char const* key_cstr{""}; GVariant* value{nullptr}; while (g_variant_iter_next(properties_iter, "{&sv}", &key_cstr, &value)) { auto const key_str = std::string{key_cstr}; if (key_str == "LidIsClosed") { auto const lid_is_closed = g_variant_get_boolean(value); log->logDebug(log_tag, "change_upower(), lid_is_closed=%s", lid_is_closed ? "true" : "false"); if (lid_is_closed) lid_handler(LidState::closed); else lid_handler(LidState::open); } g_variant_unref(value); } } GVariant* repowerd::UPowerPowerSourceAndLid::get_device_properties(std::string const& device) { int constexpr timeout_default = -1; auto constexpr null_cancellable = nullptr; ScopedGError error; auto const result = g_dbus_connection_call_sync( dbus_connection, dbus_upower_name, device.c_str(), "org.freedesktop.DBus.Properties", "GetAll", g_variant_new("(s)", "org.freedesktop.UPower.Device"), G_VARIANT_TYPE("(a{sv})"), G_DBUS_CALL_FLAGS_NONE, timeout_default, null_cancellable, error); if (!result) { log->logWarning(log_tag, "get_device_properties() failed: %s", error.message_str().c_str()); } return result; } repowerd::UPowerPowerSourceAndLid::Device repowerd::UPowerPowerSourceAndLid::create_device(std::string const& device_path) { auto properties = get_device_properties(device_path); if (!properties) return Device{}; Device device{}; device.path = device_path; GVariantIter* properties_iter; g_variant_get(properties, "(a{sv})", &properties_iter); update_device(device, properties_iter); g_variant_iter_free(properties_iter); g_variant_unref(properties); return device; } void repowerd::UPowerPowerSourceAndLid::update_device( Device& device, GVariantIter* properties_iter) { char const* key_cstr{""}; GVariant* value{nullptr}; while (g_variant_iter_next(properties_iter, "{&sv}", &key_cstr, &value)) { auto const key_str = std::string{key_cstr}; if (key_str == "Type") device.type = g_variant_get_uint32(value); else if (key_str == "IsPresent") device.is_present = g_variant_get_boolean(value); else if (key_str == "State") device.state = g_variant_get_uint32(value); else if (key_str == "Percentage") device.percentage = g_variant_get_double(value); else if (key_str == "Temperature") device.temperature = g_variant_get_double(value); g_variant_unref(value); } } void repowerd::UPowerPowerSourceAndLid::log_device( std::string const& method, Device const& device) { auto const msg = method + "(%s), type=%s, is_present=%d, state=%s, percentage=%.2f, temperature=%.2f"; log->logDebug(log_tag, msg.c_str(), device.path.c_str(), device_type_to_str(device.type).c_str(), device.is_present, device_state_to_str(device.state).c_str(), device.percentage, device.temperature); } repowerd-2023.07/src/adapters/upower_power_source_and_lid.h000066400000000000000000000064771446034100200240600ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/power_source.h" #include "src/core/lid.h" #include "dbus_connection_handle.h" #include "dbus_event_loop.h" #include #include namespace repowerd { class Log; class DeviceConfig; class TemporarySuspendInhibition; class UPowerPowerSourceAndLid : public PowerSource, public Lid { public: UPowerPowerSourceAndLid( std::shared_ptr const& log, std::shared_ptr const& temporary_suspend_inhibition, DeviceConfig const& device_config, std::string const& dbus_bus_address); void start_processing() override; HandlerRegistration register_power_source_change_handler( PowerSourceChangeHandler const& handler) override; HandlerRegistration register_power_source_critical_handler( PowerSourceCriticalHandler const& handler) override; HandlerRegistration register_lid_handler( LidHandler const& handler) override; bool is_using_battery_power() override; std::unordered_set tracked_batteries(); private: struct Device { std::string path; uint32_t type; bool is_present; uint32_t state; double percentage; double temperature; }; void handle_dbus_signal( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* signal_name, GVariant* parameters); void add_display_device(); void add_existing_batteries(); void add_device_if_battery(std::string const& device_path); void remove_device(std::string const& device_path); void change_device(std::string const& device_path, GVariantIter* properties_iter); void change_upower(GVariantIter* properties_iter); GVariant* get_device_properties(std::string const& device); Device create_device(std::string const& device_path); void update_device(Device& device, GVariantIter* properties_iter); void log_device(std::string const& method, Device const& device); std::shared_ptr const log; std::shared_ptr const temporary_suspend_inhibition; double const critical_temperature; DBusConnectionHandle dbus_connection; DBusEventLoop dbus_event_loop; HandlerRegistration dbus_signal_handler_registration; PowerSourceChangeHandler power_source_change_handler; PowerSourceChangeHandler power_source_critical_handler; LidHandler lid_handler; bool started; double highest_seen_percentage; Device display_device; std::unordered_map batteries; }; } repowerd-2023.07/src/adapters/wakeup_service.h000066400000000000000000000025461446034100200212760ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/handler_registration.h" #include #include #include namespace repowerd { using WakeupHandler = std::function; class WakeupService { public: virtual ~WakeupService() = default; virtual std::string schedule_wakeup_at(std::chrono::system_clock::time_point tp) = 0; virtual void cancel_wakeup(std::string const& cookie) = 0; virtual HandlerRegistration register_wakeup_handler(WakeupHandler const& handler) = 0; protected: WakeupService() = default; WakeupService(WakeupService const&) = delete; WakeupService& operator=(WakeupService const&) = delete; }; } repowerd-2023.07/src/core/000077500000000000000000000000001446034100200152275ustar00rootroot00000000000000repowerd-2023.07/src/core/CMakeLists.txt000066400000000000000000000016421446034100200177720ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis set( REPOWERD_CORE_SRCS daemon.cpp default_state_machine.cpp default_state_machine_factory.cpp handler_registration.cpp log.cpp state_event_adapter.cpp ) add_library( repowerd-core STATIC ${REPOWERD_CORE_SRCS} ) repowerd-2023.07/src/core/alarm_id.h000066400000000000000000000033301446034100200171470ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class AlarmId; } namespace std { template<> struct hash;} namespace repowerd { class AlarmId { public: AlarmId() : AlarmId{invalid} {} AlarmId(int id) : id{id} {} AlarmId operator++(int) { if (id == std::numeric_limits::max()) { auto const old_id = id; id = 0; return AlarmId{old_id}; } else { return AlarmId{id++}; } } bool operator==(AlarmId const& other) const { return id == other.id; } bool operator!=(AlarmId const& other) const { return !(*this == other); } static int constexpr invalid{-1}; private: friend struct std::hash; int id; }; } namespace std { template <> struct hash { size_t operator()(repowerd::AlarmId const& alarm_id) const { return std::hash{}(alarm_id.id); } }; } repowerd-2023.07/src/core/brightness_control.h000066400000000000000000000024501446034100200213110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" namespace repowerd { class BrightnessControl { public: virtual ~BrightnessControl() = default; virtual void disable_autobrightness() = 0; virtual void enable_autobrightness() = 0; virtual void set_dim_brightness() = 0; virtual void set_normal_brightness() = 0; virtual void set_normal_brightness_value(double) = 0; virtual void set_off_brightness() = 0; protected: BrightnessControl() = default; BrightnessControl (BrightnessControl const&) = default; BrightnessControl& operator=(BrightnessControl const&) = default; }; } repowerd-2023.07/src/core/client_requests.h000066400000000000000000000053651446034100200206220ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include #include #include #include namespace repowerd { using EnableInactivityTimeoutHandler = std::function; using DisableInactivityTimeoutHandler = std::function; using SetInactivityTimeoutHandler = std::function; using SetNormalBrightnessValueHandler = std::function; using EnableAutobrightnessHandler = std::function; using DisableAutobrightnessHandler = std::function; using DisallowSuspendHandler = std::function; using AllowSuspendHandler = std::function; class ClientRequests { public: virtual ~ClientRequests() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_enable_inactivity_timeout_handler( EnableInactivityTimeoutHandler const& handler) = 0; virtual HandlerRegistration register_disable_inactivity_timeout_handler( DisableInactivityTimeoutHandler const& handler) = 0; virtual HandlerRegistration register_set_inactivity_timeout_handler( SetInactivityTimeoutHandler const& handler) = 0; virtual HandlerRegistration register_set_normal_brightness_value_handler( SetNormalBrightnessValueHandler const& handler) = 0; virtual HandlerRegistration register_enable_autobrightness_handler( EnableAutobrightnessHandler const& handler) = 0; virtual HandlerRegistration register_disable_autobrightness_handler( DisableAutobrightnessHandler const& handler) = 0; virtual HandlerRegistration register_allow_suspend_handler( DisallowSuspendHandler const& handler) = 0; virtual HandlerRegistration register_disallow_suspend_handler( AllowSuspendHandler const& handler) = 0; protected: ClientRequests() = default; ClientRequests (ClientRequests const&) = default; ClientRequests& operator=(ClientRequests const&) = default; }; } repowerd-2023.07/src/core/client_settings.h000066400000000000000000000034711446034100200206030ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include "power_action.h" #include "power_supply.h" #include #include #include namespace repowerd { using SetInactivityBehaviorHandler = std::function; using SetLidBehaviorHandler = std::function; using SetCriticalPowerBehaviorHandler = std::function; class ClientSettings { public: virtual ~ClientSettings() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_set_inactivity_behavior_handler( SetInactivityBehaviorHandler const& handler) = 0; virtual HandlerRegistration register_set_lid_behavior_handler( SetLidBehaviorHandler const& handler) = 0; virtual HandlerRegistration register_set_critical_power_behavior_handler( SetCriticalPowerBehaviorHandler const& handler) = 0; protected: ClientSettings() = default; ClientSettings(ClientSettings const&) = default; ClientSettings& operator=(ClientSettings const&) = default; }; } repowerd-2023.07/src/core/daemon.cpp000066400000000000000000000457551446034100200172160ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "daemon.h" #include "brightness_control.h" #include "client_requests.h" #include "client_settings.h" #include "display_power_control.h" #include "lid.h" #include "notification_service.h" #include "null_state_machine.h" #include "power_button.h" #include "power_source.h" #include "proximity_sensor.h" #include "session_tracker.h" #include "state_machine.h" #include "state_machine_factory.h" #include "system_power_control.h" #include "timer.h" #include "user_activity.h" #include "voice_call_service.h" #include #include repowerd::Daemon::Session::Session( std::shared_ptr const& state_machine) : state_machine{state_machine}, state_event_adapter{*state_machine} { } repowerd::Daemon::Daemon(DaemonConfig& config) : brightness_control{config.the_brightness_control()}, client_requests{config.the_client_requests()}, client_settings{config.the_client_settings()}, lid{config.the_lid()}, notification_service{config.the_notification_service()}, power_button{config.the_power_button()}, power_source{config.the_power_source()}, proximity_sensor{config.the_proximity_sensor()}, session_tracker{config.the_session_tracker()}, state_machine_factory{config.the_state_machine_factory()}, system_power_control{config.the_system_power_control()}, timer{config.the_timer()}, user_activity{config.the_user_activity()}, voice_call_service{config.the_voice_call_service()}, running{false} { sessions.emplace(repowerd::invalid_session_id, Session{std::make_shared()}); active_session = &sessions.at(repowerd::invalid_session_id); } void repowerd::Daemon::run() { auto const registrations = register_event_handlers(); start_event_processing(); running = true; while (running) { auto const ev = dequeue_action(); ev(); } } void repowerd::Daemon::stop() { enqueue_priority_action([this] { running = false; }); } void repowerd::Daemon::flush() { std::promise flushed_promise; auto flushed_future = flushed_promise.get_future(); enqueue_action([&flushed_promise] { flushed_promise.set_value(); }); flushed_future.wait(); } std::vector repowerd::Daemon::register_event_handlers() { std::vector registrations; registrations.push_back( power_button->register_power_button_handler( [this] (PowerButtonState state) { if (state == PowerButtonState::pressed) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_power_button_press(); }); } else if (state == PowerButtonState::released) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_power_button_release(); } ); } })); registrations.push_back( timer->register_alarm_handler( [this] (AlarmId id) { enqueue_action_to_all_sessions( [this, id] (Session* s) { s->state_machine->handle_alarm(id); }); })); registrations.push_back( user_activity->register_user_activity_handler( [this] (UserActivityType type) { if (type == UserActivityType::change_power_state) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_user_activity_changing_power_state(); }); } else if (type == UserActivityType::extend_power_state) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_user_activity_extending_power_state(); }); } })); registrations.push_back( proximity_sensor->register_proximity_handler( [this] (ProximityState state) { if (state == ProximityState::far) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_proximity_far(); }); } else if (state == ProximityState::near) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_proximity_near(); }); } })); registrations.push_back( client_requests->register_enable_inactivity_timeout_handler( [this] (std::string const& id, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, id] (Session* s) { s->state_event_adapter.handle_enable_inactivity_timeout(id); }); })); registrations.push_back( client_requests->register_disable_inactivity_timeout_handler( [this] (std::string const& id, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, id] (Session* s) { s->state_event_adapter.handle_disable_inactivity_timeout(id); }); })); registrations.push_back( client_requests->register_set_inactivity_timeout_handler( [this] (std::chrono::milliseconds timeout, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, timeout] (Session* s) { s->state_machine->handle_set_inactivity_behavior( PowerAction::display_off, PowerSupply::battery, timeout); s->state_machine->handle_set_inactivity_behavior( PowerAction::display_off, PowerSupply::line_power, timeout); }); })); registrations.push_back( notification_service->register_notification_handler( [this] (std::string const& id, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this,id] (Session* s) { s->state_event_adapter.handle_notification(id); }); })); registrations.push_back( notification_service->register_notification_done_handler( [this] (std::string const& id, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this,id] (Session* s){ s->state_event_adapter.handle_notification_done(id); }); })); registrations.push_back( voice_call_service->register_active_call_handler( [this] { enqueue_action_to_active_session( [this] (Session* s) { add_session_with_active_call(s); s->state_machine->handle_active_call(); }); })); registrations.push_back( voice_call_service->register_no_active_call_handler( [this] { enqueue_action_to_sessions( [this] { return sessions_with_active_calls; }, [this] (Session* s) { s->state_machine->handle_no_active_call(); }); })); registrations.push_back( client_requests->register_set_normal_brightness_value_handler( [this] (double value, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this,value] (Session* s) { s->state_machine->handle_set_normal_brightness_value(value); }); })); registrations.push_back( client_requests->register_disable_autobrightness_handler( [this] (pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this] (Session* s) { s->state_machine->handle_disable_autobrightness(); }); })); registrations.push_back( client_requests->register_enable_autobrightness_handler( [this] (pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this] (Session* s) { s->state_machine->handle_enable_autobrightness(); }); })); registrations.push_back( client_requests->register_allow_suspend_handler( [this] (std::string const& id, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, id] (Session* s) { s->state_event_adapter.handle_allow_suspend(id); }); })); registrations.push_back( client_requests->register_disallow_suspend_handler( [this] (std::string const& id, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, id] (Session* s) { s->state_event_adapter.handle_disallow_suspend(id); }); })); registrations.push_back( power_source->register_power_source_change_handler( [this] { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_power_source_change(); }); })); registrations.push_back( power_source->register_power_source_critical_handler( [this] { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_power_source_critical(); }); })); registrations.push_back( session_tracker->register_active_session_changed_handler( [this] (std::string const& session_id, SessionType session_type) { enqueue_action( [this, session_id, session_type] { handle_session_activated(session_id, session_type); }); })); registrations.push_back( session_tracker->register_session_removed_handler( [this] (std::string const& session_id) { enqueue_action( [this, session_id] { handle_session_removed(session_id); }); })); registrations.push_back( lid->register_lid_handler( [this] (LidState lid_state) { if (lid_state == LidState::closed) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_lid_closed(); }); } else if (lid_state == LidState::open) { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_lid_open(); }); } })); registrations.push_back( client_settings->register_set_inactivity_behavior_handler( [this] (PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, power_action, power_supply, timeout] (Session* s) { s->state_machine->handle_set_inactivity_behavior( power_action, power_supply, timeout); }); })); registrations.push_back( client_settings->register_set_lid_behavior_handler( [this] (PowerAction power_action, PowerSupply power_supply, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, power_action, power_supply] (Session* s) { s->state_machine->handle_set_lid_behavior( power_action, power_supply); }); })); registrations.push_back( client_settings->register_set_critical_power_behavior_handler( [this] (PowerAction power_action, pid_t pid) { enqueue_action_to_sessions( sessions_for_pid(pid), [this, power_action] (Session* s) { s->state_machine->handle_set_critical_power_behavior( power_action); }); })); registrations.push_back( system_power_control->register_system_resume_handler( [this] { enqueue_action_to_active_session( [this] (Session* s) { s->state_machine->handle_system_resume(); }); })); registrations.push_back( system_power_control->register_system_allow_suspend_handler( [this] (std::string const& id) { enqueue_action_to_all_sessions( [this, id] (Session* s) { s->state_event_adapter.handle_allow_suspend(id); }); })); registrations.push_back( system_power_control->register_system_disallow_suspend_handler( [this] (std::string const& id) { enqueue_action_to_all_sessions( [this, id] (Session* s) { s->state_event_adapter.handle_disallow_suspend(id); }); })); return registrations; } void repowerd::Daemon::start_event_processing() { // Start first so that the initial active session becomes known // before per-session events (client requests and notifications) // arrive session_tracker->start_processing(); client_requests->start_processing(); client_settings->start_processing(); lid->start_processing(); notification_service->start_processing(); power_button->start_processing(); power_source->start_processing(); system_power_control->start_processing(); user_activity->start_processing(); voice_call_service->start_processing(); } void repowerd::Daemon::enqueue_action(Action const& action) { std::lock_guard lock{action_queue_mutex}; action_queue.push_back(action); action_queue_cv.notify_one(); } void repowerd::Daemon::enqueue_priority_action(Action const& action) { std::lock_guard lock{action_queue_mutex}; action_queue.push_front(action); action_queue_cv.notify_one(); } void repowerd::Daemon::enqueue_action_to_active_session( SessionAction const& session_action) { enqueue_action( [this, session_action] { session_action(active_session); }); } void repowerd::Daemon::enqueue_action_to_all_sessions( SessionAction const& session_action) { enqueue_action( [this, session_action] { for (auto& kv : sessions) session_action(&kv.second); }); } void repowerd::Daemon::enqueue_action_to_sessions( std::vector const& target_sessions, SessionAction const& session_action) { enqueue_action( [this, target_sessions, session_action] { for (auto const& session_id : target_sessions) { auto const iter = sessions.find(session_id); if (iter != sessions.end()) session_action(&iter->second); } }); } void repowerd::Daemon::enqueue_action_to_sessions( std::function()> const& sessions_func, SessionAction const& session_action) { enqueue_action( [this, sessions_func, session_action] { for (auto const& session_id : sessions_func()) { auto const iter = sessions.find(session_id); if (iter != sessions.end()) session_action(&iter->second); } }); } repowerd::Daemon::Action repowerd::Daemon::dequeue_action() { std::unique_lock lock{action_queue_mutex}; action_queue_cv.wait(lock, [this] { return !action_queue.empty(); }); auto ev = action_queue.front(); action_queue.pop_front(); return ev; } void repowerd::Daemon::handle_session_activated( std::string const& session_id, SessionType session_type) { active_session->state_machine->pause(); if (session_type == SessionType::RepowerdIncompatible) { active_session = &sessions.at(repowerd::invalid_session_id); } else { auto iter = sessions.find(session_id); if (iter == sessions.end()) { iter = sessions.emplace( session_id, Session{state_machine_factory->create_state_machine(session_id)}).first; iter->second.state_machine->start(); } else { iter->second.state_machine->resume(); } active_session = &iter->second; } } void repowerd::Daemon::handle_session_removed( std::string const& session_id) { auto const iter = sessions.find(session_id); if (iter != sessions.end()) { if (active_session == &iter->second) { active_session->state_machine->pause(); active_session = &sessions.at(repowerd::invalid_session_id); } sessions.erase(session_id); } } std::vector repowerd::Daemon::sessions_for_pid(pid_t pid) { std::vector ret; if (pid == 0) { for (auto const& kv : sessions) ret.push_back(kv.first); } else { ret.push_back(session_tracker->session_for_pid(pid)); } return ret; } void repowerd::Daemon::add_session_with_active_call(Session* session) { auto const iter = std::find_if(sessions.begin(), sessions.end(), [&] (auto const& kv) { return &kv.second == session; }); if (iter != sessions.end()) { if (std::find(sessions_with_active_calls.begin(), sessions_with_active_calls.end(), iter->first) == sessions_with_active_calls.end()) { sessions_with_active_calls.push_back(iter->first); } } } repowerd-2023.07/src/core/daemon.h000066400000000000000000000066571446034100200166610ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "daemon_config.h" #include "handler_registration.h" #include "state_event_adapter.h" #include "session_tracker.h" #include #include #include #include #include #include #include #include namespace repowerd { class Daemon { public: Daemon(DaemonConfig& config); void run(); void stop(); void flush(); private: struct Session { Session(std::shared_ptr const& state_machine); std::shared_ptr const state_machine; StateEventAdapter state_event_adapter; }; using Action = std::function; using SessionAction = std::function; std::vector register_event_handlers(); void start_event_processing(); void enqueue_action(Action const& action); void enqueue_priority_action(Action const& action); void enqueue_action_to_active_session(SessionAction const& action); void enqueue_action_to_all_sessions(SessionAction const& action); void enqueue_action_to_sessions( std::vector const& sessions, SessionAction const& action); void enqueue_action_to_sessions( std::function()> const& sessions_func, SessionAction const& action); Action dequeue_action(); void handle_session_activated(std::string const&, repowerd::SessionType); void handle_session_removed(std::string const&); std::vector sessions_for_pid(pid_t pid); void add_session_with_active_call(Session* session); std::vector session_with_active_calls(); std::shared_ptr const brightness_control; std::shared_ptr const client_requests; std::shared_ptr const client_settings; std::shared_ptr const lid; std::shared_ptr const notification_service; std::shared_ptr const power_button; std::shared_ptr const power_source; std::shared_ptr const proximity_sensor; std::shared_ptr const session_tracker; std::shared_ptr const state_machine_factory; std::shared_ptr const system_power_control; std::shared_ptr const timer; std::shared_ptr const user_activity; std::shared_ptr const voice_call_service; bool running; std::unordered_map sessions; std::vector sessions_with_active_calls; Session* active_session; std::mutex action_queue_mutex; std::condition_variable action_queue_cv; std::deque action_queue; }; } repowerd-2023.07/src/core/daemon_config.h000066400000000000000000000060341446034100200201730ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class DisplayInformation; class BrightnessControl; class ClientRequests; class ClientSettings; class DisplayPowerControl; class DisplayPowerEventSink; class Lid; class Log; class ModemPowerControl; class NotificationService; class PerformanceBooster; class PowerButton; class PowerButtonEventSink; class PowerSource; class ProximitySensor; class SessionTracker; class StateMachineFactory; class StateMachineOptions; class SystemPowerControl; class Timer; class UserActivity; class VoiceCallService; class DaemonConfig { public: virtual ~DaemonConfig() = default; virtual std::shared_ptr the_display_information() = 0; virtual std::shared_ptr the_brightness_control() = 0; virtual std::shared_ptr the_client_requests() = 0; virtual std::shared_ptr the_client_settings() = 0; virtual std::shared_ptr the_display_power_control() = 0; virtual std::shared_ptr the_display_power_event_sink() = 0; virtual std::shared_ptr the_lid() = 0; virtual std::shared_ptr the_log() = 0; virtual std::shared_ptr the_modem_power_control() = 0; virtual std::shared_ptr the_notification_service() = 0; virtual std::shared_ptr the_performance_booster() = 0; virtual std::shared_ptr the_power_button() = 0; virtual std::shared_ptr the_power_button_event_sink() = 0; virtual std::shared_ptr the_power_source() = 0; virtual std::shared_ptr the_proximity_sensor() = 0; virtual std::shared_ptr the_session_tracker() = 0; virtual std::shared_ptr the_state_machine_factory() = 0; virtual std::shared_ptr the_state_machine_options() = 0; virtual std::shared_ptr the_system_power_control() = 0; virtual std::shared_ptr the_timer() = 0; virtual std::shared_ptr the_user_activity() = 0; virtual std::shared_ptr the_voice_call_service() = 0; protected: DaemonConfig() = default; DaemonConfig(DaemonConfig const&) = delete; DaemonConfig& operator=(DaemonConfig const&) = delete; }; } repowerd-2023.07/src/core/default_state_machine.cpp000066400000000000000000000763231446034100200222560ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "default_state_machine.h" #include "display_information.h" #include "brightness_control.h" #include "display_power_control.h" #include "display_power_event_sink.h" #include "infinite_timeout.h" #include "log.h" #include "modem_power_control.h" #include "performance_booster.h" #include "power_button_event_sink.h" #include "power_source.h" #include "proximity_sensor.h" #include "state_machine_options.h" #include "system_power_control.h" #include "timer.h" namespace { char const* const suspend_id = "DefaultStateMachine"; std::string power_action_to_str(repowerd::PowerAction power_action) { if (power_action == repowerd::PowerAction::none) return "none"; else if (power_action == repowerd::PowerAction::display_off) return "display_off"; else if (power_action == repowerd::PowerAction::suspend) return "suspend"; else if (power_action == repowerd::PowerAction::power_off) return "power_off"; return "unknown"; } std::string power_supply_to_str(repowerd::PowerSupply power_supply) { if (power_supply == repowerd::PowerSupply::battery) return "battery"; else if (power_supply == repowerd::PowerSupply::line_power) return "line_power"; return "unknown"; } } repowerd::DefaultStateMachine::DefaultStateMachine( DaemonConfig& config, std::string const& name) : log_tag_str{std::string{"DefaultStateMachine["} + name + "]"}, log_tag{log_tag_str.c_str()}, display_information{config.the_display_information()}, brightness_control{config.the_brightness_control()}, display_power_control{config.the_display_power_control()}, display_power_event_sink{config.the_display_power_event_sink()}, log{config.the_log()}, modem_power_control{config.the_modem_power_control()}, performance_booster{config.the_performance_booster()}, power_button_event_sink{config.the_power_button_event_sink()}, power_source{config.the_power_source()}, proximity_sensor{config.the_proximity_sensor()}, system_power_control{config.the_system_power_control()}, timer{config.the_timer()}, display_power_mode{DisplayPowerMode::off}, display_power_mode_at_power_button_press{DisplayPowerMode::unknown}, display_power_mode_reason{DisplayPowerChangeReason::unknown}, power_button_long_press_alarm_id{AlarmId::invalid}, power_button_long_press_detected{false}, power_button_long_press_timeout{config.the_state_machine_options()->power_button_long_press_timeout()}, user_inactivity_display_dim_alarm_id{AlarmId::invalid}, user_inactivity_display_off_alarm_id{AlarmId::invalid}, user_inactivity_normal_display_dim_duration{ config.the_state_machine_options()->user_inactivity_normal_display_dim_duration()}, user_inactivity_normal_display_off_timeout{ config.the_state_machine_options()->user_inactivity_normal_display_off_timeout(), config.the_state_machine_options()->user_inactivity_normal_display_off_timeout(), true}, user_inactivity_normal_suspend_timeout{ config.the_state_machine_options()->user_inactivity_normal_suspend_timeout(), config.the_state_machine_options()->user_inactivity_normal_suspend_timeout(), true}, user_inactivity_reduced_display_off_timeout{ config.the_state_machine_options()->user_inactivity_reduced_display_off_timeout()}, user_inactivity_post_notification_display_off_timeout{ config.the_state_machine_options()->user_inactivity_post_notification_display_off_timeout()}, notification_expiration_timeout{ config.the_state_machine_options()->notification_expiration_timeout()}, treat_power_button_as_user_activity{ config.the_state_machine_options()->treat_power_button_as_user_activity()}, turn_on_display_at_startup{ config.the_state_machine_options()->turn_on_display_at_startup()}, scheduled_timeout_type{ScheduledTimeoutType::none}, lid_power_action{PowerAction::suspend, PowerAction::suspend, true}, critical_power_action{PowerAction::power_off}, paused{false}, autobrightness_enabled{false}, normal_brightness_value{0.5}, lid_closed{false}, suspend_allowed{true}, suspend_pending{false} { inactivity_timeout_allowances.fill(true); proximity_enablements.fill(false); } void repowerd::DefaultStateMachine::handle_alarm(AlarmId id) { if (id == power_button_long_press_alarm_id) { log->logDebug(log_tag, "handle_alarm(long_press)"); power_button_event_sink->notify_long_press(); power_button_long_press_detected = true; power_button_long_press_alarm_id = AlarmId::invalid; } else if (id == user_inactivity_display_dim_alarm_id) { log->logDebug(log_tag, "handle_alarm(display_dim)"); user_inactivity_display_dim_alarm_id = AlarmId::invalid; if (is_inactivity_timeout_application_allowed()) dim_display(); } else if (id == user_inactivity_display_off_alarm_id) { log->logDebug(log_tag, "handle_alarm(display_off)"); user_inactivity_display_off_alarm_id = AlarmId::invalid; if (is_inactivity_timeout_application_allowed()) turn_off_display(DisplayPowerChangeReason::activity); scheduled_timeout_type = ScheduledTimeoutType::none; } else if (id == user_inactivity_suspend_alarm_id) { log->logDebug(log_tag, "handle_alarm(suspend)"); user_inactivity_suspend_alarm_id = AlarmId::invalid; if (is_inactivity_timeout_application_allowed()) suspend_when_allowed(); } else if (id == proximity_disable_alarm_id) { log->logDebug(log_tag, "handle_alarm(proximity_disable)"); proximity_disable_alarm_id = AlarmId::invalid; disable_proximity(ProximityEnablement::until_far_event_or_timeout); } else if (id == notification_expiration_alarm_id) { log->logDebug(log_tag, "handle_alarm(notification_expiration)"); notification_expiration_alarm_id = AlarmId::invalid; if (display_power_mode == DisplayPowerMode::on) schedule_immediate_user_inactivity_alarm(); allow_inactivity_timeout(InactivityTimeoutAllowance::notification); disable_proximity(ProximityEnablement::until_far_event_or_notification_expiration); } else if (id == suspend_delay_alarm_id) { log->logDebug(log_tag, "handle_alarm(suspend_delay)"); suspend_delay_alarm_id = AlarmId::invalid; if (display_power_mode == DisplayPowerMode::off && display_power_mode_reason != DisplayPowerChangeReason::proximity && suspend_allowed) system_power_control->allow_automatic_suspend(suspend_id); } } void repowerd::DefaultStateMachine::handle_active_call() { log->logDebug(log_tag, "handle_active_call"); if (display_power_mode == DisplayPowerMode::on) { brighten_display(); schedule_normal_user_inactivity_alarm(); } else if (proximity_sensor->proximity_state() == ProximityState::far) { turn_on_display_with_normal_timeout(DisplayPowerChangeReason::call); } enable_proximity(ProximityEnablement::until_disabled); } void repowerd::DefaultStateMachine::handle_no_active_call() { log->logDebug(log_tag, "handle_no_active_call"); if (display_power_mode == DisplayPowerMode::on) { brighten_display(); schedule_reduced_user_inactivity_alarm(); } else { if (proximity_sensor->proximity_state() == ProximityState::far) { turn_on_display_with_reduced_timeout(DisplayPowerChangeReason::call_done); } else { enable_proximity(ProximityEnablement::until_far_event_or_timeout); schedule_proximity_disable_alarm(); } } disable_proximity(ProximityEnablement::until_disabled); } void repowerd::DefaultStateMachine::handle_enable_inactivity_timeout() { log->logDebug(log_tag, "handle_enable_inactivity_timeout"); allow_inactivity_timeout(InactivityTimeoutAllowance::client); } void repowerd::DefaultStateMachine::handle_disable_inactivity_timeout() { log->logDebug(log_tag, "handle_disable_inactivity_timeout"); disallow_inactivity_timeout(InactivityTimeoutAllowance::client); if (display_power_mode == DisplayPowerMode::on) { brighten_display(); } else { turn_on_display_without_timeout(DisplayPowerChangeReason::unknown); } } void repowerd::DefaultStateMachine::handle_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout) { log->logDebug(log_tag, "handle_set_inactivity_behavior(%s,%s,%ld)", power_action_to_str(power_action).c_str(), power_supply_to_str(power_supply).c_str(), static_cast(timeout.count())); if (timeout <= std::chrono::milliseconds::zero()) return; if (power_action != PowerAction::display_off && power_action != PowerAction::suspend) { return; } bool power_supply_is_active{false}; auto& inactivity_timeout = power_action == PowerAction::display_off ? user_inactivity_normal_display_off_timeout : user_inactivity_normal_suspend_timeout; if (power_supply == PowerSupply::battery) { inactivity_timeout.on_battery = timeout; power_supply_is_active = user_inactivity_normal_display_off_timeout.is_on_battery; } else { inactivity_timeout.on_line_power = timeout; power_supply_is_active = !user_inactivity_normal_display_off_timeout.is_on_battery; } if (scheduled_timeout_type == ScheduledTimeoutType::normal && power_supply_is_active) schedule_normal_user_inactivity_alarm(); } void repowerd::DefaultStateMachine::handle_lid_closed() { log->logDebug(log_tag, "handle_lid_closed()"); lid_closed = true; if (!display_information->has_active_external_displays()) { if (display_power_mode == DisplayPowerMode::on) turn_off_display(DisplayPowerChangeReason::unknown); if (lid_power_action.get() == PowerAction::suspend) system_power_control->suspend(); } else { display_power_control->turn_off(DisplayPowerControlFilter::internal); } } void repowerd::DefaultStateMachine::handle_lid_open() { log->logDebug(log_tag, "handle_lid_open()"); lid_closed = false; if (display_power_mode == DisplayPowerMode::on) { display_power_control->turn_on(DisplayPowerControlFilter::internal); brighten_display(); schedule_normal_user_inactivity_alarm(); display_power_mode_reason = DisplayPowerChangeReason::activity; } else { turn_on_display_with_normal_timeout(DisplayPowerChangeReason::activity); } } void repowerd::DefaultStateMachine::handle_set_lid_behavior( PowerAction power_action, PowerSupply power_supply) { log->logDebug(log_tag, "handle_set_lid_behavior(%s,%s)", power_action_to_str(power_action).c_str(), power_supply_to_str(power_supply).c_str()); if (power_action != PowerAction::none && power_action != PowerAction::suspend) { return; } if (power_supply == PowerSupply::battery) lid_power_action.on_battery = power_action; else lid_power_action.on_line_power = power_action; } void repowerd::DefaultStateMachine::handle_set_critical_power_behavior( PowerAction power_action) { log->logDebug(log_tag, "handle_set_critical_power_behavior(%s)", power_action_to_str(power_action).c_str()); if (power_action != PowerAction::suspend && power_action != PowerAction::power_off) { return; } critical_power_action = power_action; } void repowerd::DefaultStateMachine::handle_no_notification() { log->logDebug(log_tag, "handle_no_notification"); if (display_power_mode == DisplayPowerMode::on) { schedule_post_notification_user_inactivity_alarm(); } allow_inactivity_timeout(InactivityTimeoutAllowance::notification); disable_proximity(ProximityEnablement::until_far_event_or_notification_expiration); cancel_notification_expiration_alarm(); } void repowerd::DefaultStateMachine::handle_notification() { log->logDebug(log_tag, "handle_notification"); disallow_inactivity_timeout(InactivityTimeoutAllowance::notification); if (display_power_mode == DisplayPowerMode::on) { brighten_display(); } else { if (proximity_sensor->proximity_state() == ProximityState::far) { turn_on_display_without_timeout(DisplayPowerChangeReason::notification); } else { enable_proximity(ProximityEnablement::until_far_event_or_notification_expiration); } } schedule_notification_expiration_alarm(); } void repowerd::DefaultStateMachine::handle_power_button_press() { log->logDebug(log_tag, "handle_power_button_press"); display_power_mode_at_power_button_press = display_power_mode; if (treat_power_button_as_user_activity && display_power_mode == DisplayPowerMode::on) { brighten_display(); schedule_normal_user_inactivity_alarm(); display_power_mode_reason = DisplayPowerChangeReason::power_button; } else if (display_power_mode == DisplayPowerMode::off) { turn_on_display_with_normal_timeout(DisplayPowerChangeReason::power_button); } power_button_long_press_alarm_id = timer->schedule_alarm_in(power_button_long_press_timeout); } void repowerd::DefaultStateMachine::handle_power_button_release() { log->logDebug(log_tag, "handle_power_button_release"); if (power_button_long_press_detected) { power_button_long_press_detected = false; } else if (display_power_mode_at_power_button_press == DisplayPowerMode::on && !treat_power_button_as_user_activity) { turn_off_display(DisplayPowerChangeReason::power_button); } display_power_mode_at_power_button_press = DisplayPowerMode::unknown; power_button_long_press_alarm_id = AlarmId::invalid; } void repowerd::DefaultStateMachine::handle_power_source_change() { log->logDebug(log_tag, "handle_power_source_change"); auto const is_on_battery = power_source->is_using_battery_power(); user_inactivity_normal_display_off_timeout.is_on_battery = is_on_battery; user_inactivity_normal_suspend_timeout.is_on_battery = is_on_battery; lid_power_action.is_on_battery = is_on_battery; if (display_power_mode == DisplayPowerMode::on) { brighten_display(); schedule_normal_user_inactivity_alarm(); display_power_mode_reason = DisplayPowerChangeReason::activity; } else if (proximity_sensor->proximity_state() == ProximityState::far) { turn_on_display_with_reduced_timeout(DisplayPowerChangeReason::notification); } schedule_normal_user_inactivity_suspend_alarm(); } void repowerd::DefaultStateMachine::handle_power_source_critical() { log->logDebug(log_tag, "handle_power_source_critical"); if (critical_power_action == PowerAction::power_off) system_power_control->power_off(); else if (critical_power_action == PowerAction::suspend) system_power_control->suspend(); } void repowerd::DefaultStateMachine::handle_proximity_far() { log->logDebug(log_tag, "handle_proximity_far"); auto const use_reduced_timeout = is_proximity_enabled_only_until_far_event_or_notification_expiration(); disable_proximity(ProximityEnablement::until_far_event_or_notification_expiration); disable_proximity(ProximityEnablement::until_far_event_or_timeout); if (display_power_mode == DisplayPowerMode::off) { if (use_reduced_timeout) { turn_on_display_with_reduced_timeout(DisplayPowerChangeReason::proximity); } else { turn_on_display_with_normal_timeout(DisplayPowerChangeReason::proximity); } } } void repowerd::DefaultStateMachine::handle_proximity_near() { log->logDebug(log_tag, "handle_proximity_near"); if (display_power_mode == DisplayPowerMode::on) turn_off_display(DisplayPowerChangeReason::proximity); } void repowerd::DefaultStateMachine::handle_user_activity_changing_power_state() { log->logDebug(log_tag, "handle_user_activity_changing_power_state"); if (display_power_mode == DisplayPowerMode::on) { brighten_display(); schedule_normal_user_inactivity_alarm(); display_power_mode_reason = DisplayPowerChangeReason::activity; } else if (proximity_sensor->proximity_state() == ProximityState::far) { turn_on_display_with_normal_timeout(DisplayPowerChangeReason::activity); } } void repowerd::DefaultStateMachine::handle_user_activity_extending_power_state() { log->logDebug(log_tag, "handle_user_activity_extending_power_state"); if (display_power_mode == DisplayPowerMode::on) { brighten_display(); schedule_normal_user_inactivity_alarm(); display_power_mode_reason = DisplayPowerChangeReason::activity; } } void repowerd::DefaultStateMachine::handle_set_normal_brightness_value(double value) { log->logDebug(log_tag, "handle_set_normal_brightness_value(%.2f)", value); normal_brightness_value = value; if (paused) return; brightness_control->set_normal_brightness_value(value); } void repowerd::DefaultStateMachine::handle_enable_autobrightness() { log->logDebug(log_tag, "enable_autobrightness"); autobrightness_enabled = true; if (paused) return; brightness_control->enable_autobrightness(); } void repowerd::DefaultStateMachine::handle_disable_autobrightness() { log->logDebug(log_tag, "disable_autobrightness"); autobrightness_enabled = false; if (paused) return; brightness_control->disable_autobrightness(); } void repowerd::DefaultStateMachine::handle_allow_suspend(std::string id) { log->logDebug(log_tag, "allow_suspend(id=%s)", id.c_str()); suspend_allowed = true; if (display_power_mode == DisplayPowerMode::off && display_power_mode_reason != DisplayPowerChangeReason::proximity) suspend_delay_alarm_id = timer->schedule_alarm_in(std::chrono::milliseconds{4000}); if (suspend_pending) suspend_when_allowed(); } void repowerd::DefaultStateMachine::handle_disallow_suspend(std::string id) { log->logDebug(log_tag, "disallow_suspend(id=%s)", id.c_str()); suspend_allowed = false; cancel_suspend_delay_alarm(); system_power_control->disallow_automatic_suspend(suspend_id); } void repowerd::DefaultStateMachine::handle_system_resume() { log->logDebug(log_tag, "handle_system_resume"); turn_on_display_with_normal_timeout(DisplayPowerChangeReason::activity); } void repowerd::DefaultStateMachine::start() { log->logDebug(log_tag, "start"); auto const is_on_battery = power_source->is_using_battery_power(); user_inactivity_normal_display_off_timeout.is_on_battery = is_on_battery; user_inactivity_normal_suspend_timeout.is_on_battery = is_on_battery; lid_power_action.is_on_battery = is_on_battery; system_power_control->disallow_default_system_handlers(); if (turn_on_display_at_startup) turn_on_display_with_normal_timeout(DisplayPowerChangeReason::unknown); } void repowerd::DefaultStateMachine::pause() { log->logDebug(log_tag, "pause"); if (power_button_long_press_alarm_id != AlarmId::invalid) { timer->cancel_alarm(power_button_long_press_alarm_id); power_button_long_press_alarm_id = AlarmId::invalid; } cancel_suspend_delay_alarm(); proximity_sensor->disable_proximity_events(); brightness_control->disable_autobrightness(); system_power_control->allow_default_system_handlers(); paused = true; } void repowerd::DefaultStateMachine::resume() { log->logDebug(log_tag, "resume"); paused = false; system_power_control->disallow_default_system_handlers(); if (autobrightness_enabled) brightness_control->enable_autobrightness(); else brightness_control->disable_autobrightness(); brightness_control->set_normal_brightness_value(normal_brightness_value); turn_on_display_with_normal_timeout(DisplayPowerChangeReason::unknown); if (is_proximity_enabled()) proximity_sensor->enable_proximity_events(); } void repowerd::DefaultStateMachine::cancel_user_inactivity_display_off_alarm() { if (user_inactivity_display_dim_alarm_id != AlarmId::invalid) { timer->cancel_alarm(user_inactivity_display_dim_alarm_id); user_inactivity_display_dim_alarm_id = AlarmId::invalid; } if (user_inactivity_display_off_alarm_id != AlarmId::invalid) { timer->cancel_alarm(user_inactivity_display_off_alarm_id); user_inactivity_display_off_alarm_id = AlarmId::invalid; } user_inactivity_display_off_time_point = {}; scheduled_timeout_type = ScheduledTimeoutType::none; } void repowerd::DefaultStateMachine::cancel_user_inactivity_suspend_alarm() { if (user_inactivity_suspend_alarm_id != AlarmId::invalid) { timer->cancel_alarm(user_inactivity_suspend_alarm_id); user_inactivity_suspend_alarm_id = AlarmId::invalid; } } void repowerd::DefaultStateMachine::cancel_notification_expiration_alarm() { if (notification_expiration_alarm_id != AlarmId::invalid) { timer->cancel_alarm(notification_expiration_alarm_id); notification_expiration_alarm_id = AlarmId::invalid; } } void repowerd::DefaultStateMachine::cancel_suspend_delay_alarm() { if (suspend_delay_alarm_id != AlarmId::invalid) { timer->cancel_alarm(suspend_delay_alarm_id); suspend_delay_alarm_id = AlarmId::invalid; } } void repowerd::DefaultStateMachine::schedule_normal_user_inactivity_alarm() { schedule_normal_user_inactivity_display_off_alarm(); schedule_normal_user_inactivity_suspend_alarm(); } void repowerd::DefaultStateMachine::schedule_normal_user_inactivity_display_off_alarm() { cancel_user_inactivity_display_off_alarm(); scheduled_timeout_type = ScheduledTimeoutType::normal; if (user_inactivity_normal_display_off_timeout.get() == repowerd::infinite_timeout) { user_inactivity_display_off_time_point = std::chrono::steady_clock::time_point::max(); } else { user_inactivity_display_off_time_point = timer->now() + user_inactivity_normal_display_off_timeout.get(); if (user_inactivity_normal_display_off_timeout.get() > user_inactivity_normal_display_dim_duration) { user_inactivity_display_dim_alarm_id = timer->schedule_alarm_in( user_inactivity_normal_display_off_timeout.get() - user_inactivity_normal_display_dim_duration); } user_inactivity_display_off_alarm_id = timer->schedule_alarm_in(user_inactivity_normal_display_off_timeout.get()); } } void repowerd::DefaultStateMachine::schedule_normal_user_inactivity_suspend_alarm() { cancel_user_inactivity_suspend_alarm(); cancel_suspend_when_allowed(); if (user_inactivity_normal_suspend_timeout.get() != repowerd::infinite_timeout) { user_inactivity_suspend_alarm_id = timer->schedule_alarm_in(user_inactivity_normal_suspend_timeout.get()); } } void repowerd::DefaultStateMachine::schedule_post_notification_user_inactivity_alarm() { auto const tp = timer->now() + user_inactivity_post_notification_display_off_timeout; if (tp > user_inactivity_display_off_time_point) { cancel_user_inactivity_display_off_alarm(); user_inactivity_display_off_alarm_id = timer->schedule_alarm_in(user_inactivity_post_notification_display_off_timeout); user_inactivity_display_off_time_point = tp; scheduled_timeout_type = ScheduledTimeoutType::post_notification; } } void repowerd::DefaultStateMachine::schedule_reduced_user_inactivity_alarm() { auto const tp = timer->now() + user_inactivity_reduced_display_off_timeout; if (tp > user_inactivity_display_off_time_point) { cancel_user_inactivity_display_off_alarm(); user_inactivity_display_off_alarm_id = timer->schedule_alarm_in(user_inactivity_reduced_display_off_timeout); user_inactivity_display_off_time_point = tp; scheduled_timeout_type = ScheduledTimeoutType::reduced; } } void repowerd::DefaultStateMachine::schedule_proximity_disable_alarm() { if (proximity_disable_alarm_id != AlarmId::invalid) timer->cancel_alarm(proximity_disable_alarm_id); proximity_disable_alarm_id = timer->schedule_alarm_in(user_inactivity_reduced_display_off_timeout); } void repowerd::DefaultStateMachine::schedule_notification_expiration_alarm() { cancel_notification_expiration_alarm(); auto const timeout = std::min( user_inactivity_normal_display_off_timeout.get(), notification_expiration_timeout); notification_expiration_alarm_id = timer->schedule_alarm_in(timeout); } void repowerd::DefaultStateMachine::schedule_immediate_user_inactivity_alarm() { auto const tp = timer->now(); if (tp > user_inactivity_display_off_time_point) { cancel_user_inactivity_display_off_alarm(); user_inactivity_display_off_alarm_id = timer->schedule_alarm_in(std::chrono::milliseconds{0}); user_inactivity_display_off_time_point = tp; scheduled_timeout_type = ScheduledTimeoutType::post_notification; } } void repowerd::DefaultStateMachine::turn_off_display( DisplayPowerChangeReason reason) { if (paused) return; brightness_control->set_off_brightness(); display_power_control->turn_off(DisplayPowerControlFilter::all); if (reason != DisplayPowerChangeReason::proximity) modem_power_control->set_low_power_mode(); display_power_mode = DisplayPowerMode::off; display_power_mode_reason = reason; cancel_user_inactivity_display_off_alarm(); display_power_event_sink->notify_display_power_off(reason); performance_booster->disable_interactive_mode(); if (reason != DisplayPowerChangeReason::proximity && suspend_allowed) suspend_delay_alarm_id = timer->schedule_alarm_in(std::chrono::milliseconds{4000}); } void repowerd::DefaultStateMachine::turn_on_display_without_timeout( DisplayPowerChangeReason reason) { if (paused) return; system_power_control->disallow_automatic_suspend(suspend_id); performance_booster->enable_interactive_mode(); if (lid_closed) display_power_control->turn_on(DisplayPowerControlFilter::external); else display_power_control->turn_on(DisplayPowerControlFilter::all); display_power_mode = DisplayPowerMode::on; display_power_mode_reason = reason; if (!lid_closed) brighten_display(); modem_power_control->set_normal_power_mode(); display_power_event_sink->notify_display_power_on(reason); } void repowerd::DefaultStateMachine::turn_on_display_with_normal_timeout( DisplayPowerChangeReason reason) { turn_on_display_without_timeout(reason); schedule_normal_user_inactivity_alarm(); } void repowerd::DefaultStateMachine::turn_on_display_with_reduced_timeout( DisplayPowerChangeReason reason) { turn_on_display_without_timeout(reason); schedule_reduced_user_inactivity_alarm(); } void repowerd::DefaultStateMachine::brighten_display() { if (paused) return; brightness_control->set_normal_brightness(); } void repowerd::DefaultStateMachine::dim_display() { if (paused) return; brightness_control->set_dim_brightness(); } void repowerd::DefaultStateMachine::allow_inactivity_timeout( InactivityTimeoutAllowance allowance) { if (!is_inactivity_timeout_allowed()) { inactivity_timeout_allowances[allowance] = true; if (is_inactivity_timeout_allowed() && display_power_mode == DisplayPowerMode::on) { if (allowance == InactivityTimeoutAllowance::notification && scheduled_timeout_type == ScheduledTimeoutType::none) { turn_off_display(DisplayPowerChangeReason::activity); } else if (allowance == InactivityTimeoutAllowance::client) { schedule_normal_user_inactivity_alarm(); } } } } void repowerd::DefaultStateMachine::disallow_inactivity_timeout( InactivityTimeoutAllowance allowance) { inactivity_timeout_allowances[allowance] = false; } bool repowerd::DefaultStateMachine::is_inactivity_timeout_allowed() { auto const client = inactivity_timeout_allowances[InactivityTimeoutAllowance::client]; auto const notification = inactivity_timeout_allowances[InactivityTimeoutAllowance::notification]; return notification && client; } bool repowerd::DefaultStateMachine::is_inactivity_timeout_application_allowed() { if (is_inactivity_timeout_allowed()) return true; if (display_power_mode_reason == DisplayPowerChangeReason::notification || display_power_mode_reason == DisplayPowerChangeReason::call) { return true; } return false; } void repowerd::DefaultStateMachine::enable_proximity( ProximityEnablement enablement) { auto const proximity_previously_enabled = is_proximity_enabled(); proximity_enablements[enablement] = true; if (!proximity_previously_enabled && is_proximity_enabled()) { proximity_sensor->enable_proximity_events(); } } void repowerd::DefaultStateMachine::disable_proximity( ProximityEnablement enablement) { auto const proximity_previously_enabled = is_proximity_enabled(); proximity_enablements[enablement] = false; if (proximity_previously_enabled && !is_proximity_enabled()) { proximity_sensor->disable_proximity_events(); } } bool repowerd::DefaultStateMachine::is_proximity_enabled() { for (auto const& enabled : proximity_enablements) if (enabled) return true; return false; } bool repowerd::DefaultStateMachine::is_proximity_enabled_only_until_far_event_or_notification_expiration() { auto num_enabled = 0; for (auto const& enabled : proximity_enablements) if (enabled) ++num_enabled; return num_enabled == 1 && proximity_enablements[ProximityEnablement::until_far_event_or_notification_expiration]; } void repowerd::DefaultStateMachine::suspend_when_allowed() { if (suspend_allowed) { suspend_pending = false; if (!paused) system_power_control->suspend(); } else { suspend_pending = true; } } void repowerd::DefaultStateMachine::cancel_suspend_when_allowed() { suspend_pending = false; } repowerd-2023.07/src/core/default_state_machine.h000066400000000000000000000166531446034100200217230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "state_machine.h" #include "daemon_config.h" #include "display_power_change_reason.h" #include #include namespace repowerd { class DefaultStateMachine : public StateMachine { public: DefaultStateMachine(DaemonConfig& config, std::string const& name); void handle_alarm(AlarmId id) override; void handle_active_call() override; void handle_no_active_call() override; void handle_enable_inactivity_timeout() override; void handle_disable_inactivity_timeout() override; void handle_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout) override; void handle_lid_closed() override; void handle_lid_open() override; void handle_set_lid_behavior( PowerAction power_action, PowerSupply power_supply) override; void handle_no_notification() override; void handle_notification() override; void handle_power_button_press() override; void handle_power_button_release() override; void handle_power_source_change() override; void handle_power_source_critical() override; void handle_set_critical_power_behavior( PowerAction power_action) override; void handle_proximity_far() override; void handle_proximity_near() override; void handle_user_activity_changing_power_state() override; void handle_user_activity_extending_power_state() override; void handle_set_normal_brightness_value(double value) override; void handle_enable_autobrightness() override; void handle_disable_autobrightness() override; void handle_allow_suspend(std::string id) override; void handle_disallow_suspend(std::string id) override; void handle_system_resume() override; void start() override; void pause() override; void resume() override; private: enum class DisplayPowerMode {unknown, on, off}; struct InactivityTimeoutAllowanceEnum { enum Allowance {client, notification, count}; }; using InactivityTimeoutAllowance = InactivityTimeoutAllowanceEnum::Allowance; struct ProximityEnablementEnum { enum Enablement { until_far_event_or_notification_expiration, until_disabled, until_far_event_or_timeout, count}; }; using ProximityEnablement = ProximityEnablementEnum::Enablement; enum class ScheduledTimeoutType {none, normal, post_notification, reduced}; template struct ConfigurableValue { T get() const { return is_on_battery ? on_battery : on_line_power; } T on_battery; T on_line_power; bool is_on_battery{true}; }; using ConfigurableTimeout = ConfigurableValue; using ConfigurablePowerAction = ConfigurableValue; void cancel_user_inactivity_display_off_alarm(); void cancel_user_inactivity_suspend_alarm(); void cancel_notification_expiration_alarm(); void schedule_normal_user_inactivity_alarm(); void schedule_normal_user_inactivity_display_off_alarm(); void schedule_normal_user_inactivity_suspend_alarm(); void schedule_post_notification_user_inactivity_alarm(); void schedule_reduced_user_inactivity_alarm(); void schedule_proximity_disable_alarm(); void schedule_notification_expiration_alarm(); void schedule_immediate_user_inactivity_alarm(); void turn_off_display(DisplayPowerChangeReason reason); void turn_on_display_without_timeout(DisplayPowerChangeReason reason); void turn_on_display_with_normal_timeout(DisplayPowerChangeReason reason); void turn_on_display_with_reduced_timeout(DisplayPowerChangeReason reason); void brighten_display(); void dim_display(); void allow_inactivity_timeout(InactivityTimeoutAllowance allowance); void disallow_inactivity_timeout(InactivityTimeoutAllowance allowance); bool is_inactivity_timeout_allowed(); bool is_inactivity_timeout_application_allowed(); void enable_proximity(ProximityEnablement enablement); void disable_proximity(ProximityEnablement enablement); bool is_proximity_enabled(); bool is_proximity_enabled_only_until_far_event_or_notification_expiration(); void suspend_when_allowed(); void cancel_suspend_when_allowed(); void cancel_suspend_delay_alarm(); std::string const log_tag_str; char const* const log_tag; std::shared_ptr const display_information; std::shared_ptr const brightness_control; std::shared_ptr const display_power_control; std::shared_ptr const display_power_event_sink; std::shared_ptr const log; std::shared_ptr const modem_power_control; std::shared_ptr const performance_booster; std::shared_ptr const power_button_event_sink; std::shared_ptr const power_source; std::shared_ptr const proximity_sensor; std::shared_ptr const system_power_control; std::shared_ptr const timer; std::array inactivity_timeout_allowances; std::array proximity_enablements; DisplayPowerMode display_power_mode; DisplayPowerMode display_power_mode_at_power_button_press; DisplayPowerChangeReason display_power_mode_reason; AlarmId power_button_long_press_alarm_id; bool power_button_long_press_detected; std::chrono::milliseconds power_button_long_press_timeout; AlarmId user_inactivity_display_dim_alarm_id; AlarmId user_inactivity_display_off_alarm_id; AlarmId user_inactivity_suspend_alarm_id; AlarmId proximity_disable_alarm_id; AlarmId notification_expiration_alarm_id; std::chrono::steady_clock::time_point user_inactivity_display_off_time_point; std::chrono::milliseconds const user_inactivity_normal_display_dim_duration; ConfigurableTimeout user_inactivity_normal_display_off_timeout; ConfigurableTimeout user_inactivity_normal_suspend_timeout; std::chrono::milliseconds const user_inactivity_reduced_display_off_timeout; std::chrono::milliseconds const user_inactivity_post_notification_display_off_timeout; std::chrono::milliseconds const notification_expiration_timeout; bool const treat_power_button_as_user_activity; bool const turn_on_display_at_startup; ScheduledTimeoutType scheduled_timeout_type; ConfigurablePowerAction lid_power_action; PowerAction critical_power_action; AlarmId suspend_delay_alarm_id; bool paused; bool autobrightness_enabled; double normal_brightness_value; bool lid_closed; bool suspend_allowed; bool suspend_pending; }; } repowerd-2023.07/src/core/default_state_machine_factory.cpp000066400000000000000000000021411446034100200237700ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "default_state_machine_factory.h" #include "default_state_machine.h" repowerd::DefaultStateMachineFactory::DefaultStateMachineFactory( DaemonConfig& daemon_config) : daemon_config(daemon_config) { } std::shared_ptr repowerd::DefaultStateMachineFactory::create_state_machine(std::string const& name) { return std::make_shared(daemon_config, name); } repowerd-2023.07/src/core/default_state_machine_factory.h000066400000000000000000000020361446034100200234400ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "state_machine_factory.h" namespace repowerd { class DaemonConfig; class DefaultStateMachineFactory : public StateMachineFactory { public: DefaultStateMachineFactory(DaemonConfig&); std::shared_ptr create_state_machine(std::string const& name) override; private: DaemonConfig& daemon_config; }; } repowerd-2023.07/src/core/display_information.h000066400000000000000000000020461446034100200214540ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { class DisplayInformation { public: virtual ~DisplayInformation() = default; virtual bool has_active_external_displays() = 0; protected: DisplayInformation() = default; DisplayInformation (DisplayInformation const&) = default; DisplayInformation& operator=(DisplayInformation const&) = default; }; } repowerd-2023.07/src/core/display_power_change_reason.h000066400000000000000000000015661446034100200231450ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { enum class DisplayPowerChangeReason { unknown, power_button, activity, proximity, notification, call, call_done }; } repowerd-2023.07/src/core/display_power_control.h000066400000000000000000000022751446034100200220270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { enum class DisplayPowerControlFilter { all, internal, external }; class DisplayPowerControl { public: virtual ~DisplayPowerControl() = default; virtual void turn_on(DisplayPowerControlFilter filter) = 0; virtual void turn_off(DisplayPowerControlFilter filter) = 0; protected: DisplayPowerControl() = default; DisplayPowerControl (DisplayPowerControl const&) = default; DisplayPowerControl& operator=(DisplayPowerControl const&) = default; }; } repowerd-2023.07/src/core/display_power_event_sink.h000066400000000000000000000023141446034100200225060ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "display_power_change_reason.h" namespace repowerd { class DisplayPowerEventSink { public: virtual ~DisplayPowerEventSink() = default; virtual void notify_display_power_off(DisplayPowerChangeReason reason) = 0; virtual void notify_display_power_on(DisplayPowerChangeReason reason) = 0; protected: DisplayPowerEventSink() = default; DisplayPowerEventSink(DisplayPowerEventSink const&) = delete; DisplayPowerEventSink& operator=(DisplayPowerEventSink const&) = delete; }; } repowerd-2023.07/src/core/double_tap_to_wake.h000066400000000000000000000026251446034100200212340ustar00rootroot00000000000000/* * Copyright © 2022 UBports foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexander Martinz */ #pragma once #include "src/adapters/filesystem.h" #include "src/core/log.h" #include #include #include #include namespace repowerd { class Log; class Filesystem; class DoubleTapToWake { public: virtual ~DoubleTapToWake() = default; virtual bool is_enabled() = 0; virtual bool is_supported() = 0; virtual void enable() = 0; virtual void disable() = 0; protected: DoubleTapToWake() = default; DoubleTapToWake (DoubleTapToWake const&) = default; DoubleTapToWake& operator=(DoubleTapToWake const&) = default; std::shared_ptr const log; std::shared_ptr const filesystem; virtual void set_enabled(bool) = 0; }; }repowerd-2023.07/src/core/handler_registration.cpp000066400000000000000000000027731446034100200221530ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "handler_registration.h" namespace { auto const null_unregister = []{}; } repowerd::HandlerRegistration::HandlerRegistration() : unregister{null_unregister} { } repowerd::HandlerRegistration::HandlerRegistration(std::function const& unregister) : unregister{unregister} { } repowerd::HandlerRegistration::~HandlerRegistration() { unregister(); } repowerd::HandlerRegistration::HandlerRegistration(HandlerRegistration&& other) : unregister{std::move(other.unregister)} { other.unregister = null_unregister; } repowerd::HandlerRegistration& repowerd::HandlerRegistration::operator=(HandlerRegistration&& other) { if (&other != this) { unregister(); unregister = std::move(other.unregister); other.unregister = null_unregister; } return *this; } repowerd-2023.07/src/core/handler_registration.h000066400000000000000000000021311446034100200216040ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class HandlerRegistration { public: HandlerRegistration(); HandlerRegistration(std::function const& unregister); HandlerRegistration(HandlerRegistration&& other); HandlerRegistration& operator=(HandlerRegistration&& other); ~HandlerRegistration(); private: std::function unregister; }; } repowerd-2023.07/src/core/infinite_timeout.h000066400000000000000000000015151446034100200207550ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { std::chrono::milliseconds const infinite_timeout = std::chrono::milliseconds::max(); } repowerd-2023.07/src/core/lid.h000066400000000000000000000022421446034100200161500ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { enum class LidState { closed, open }; using LidHandler = std::function; class Lid { public: virtual ~Lid() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_lid_handler( LidHandler const& handler) = 0; protected: Lid() = default; Lid(Lid const&) = default; Lid& operator=(Lid const&) = default; }; } repowerd-2023.07/src/core/log.cpp000066400000000000000000000036551446034100200165250ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * Copyright © Guido Berhoerster * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis , * Guido Berhoerster */ #include "log.h" #include void repowerd::Log::vlogLevel(LogLevel level, char const* tag, char const* format, va_list ap) { if (level < m_threshold) return; logOutput(level, tag, format, ap); } void repowerd::Log::logLevel(repowerd::LogLevel level, char const* tag, char const* format, ...) { va_list ap; va_start(ap, format); vlogLevel(level, tag, format, ap); va_end(ap); } void repowerd::Log::log(char const* tag, char const* format, ...) { va_list ap; va_start(ap, format); vlogLevel(LogLevel::Info, tag, format, ap); va_end(ap); } void repowerd::Log::logDebug(char const* tag, char const* format, ...) { va_list ap; va_start(ap, format); vlogLevel(LogLevel::Debug, tag, format, ap); va_end(ap); } void repowerd::Log::logInfo(char const* tag, char const* format, ...) { va_list ap; va_start(ap, format); vlogLevel(LogLevel::Info, tag, format, ap); va_end(ap); } void repowerd::Log::logWarning(char const* tag, char const* format, ...) { va_list ap; va_start(ap, format); vlogLevel(LogLevel::Warning, tag, format, ap); va_end(ap); } repowerd-2023.07/src/core/log.h000066400000000000000000000033531446034100200161650ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { enum class LogLevel { Debug, Info, Warning }; class Log { public: virtual ~Log() = default; virtual void logOutput(LogLevel level, char const* tag, char const* format, va_list ap) = 0; void vlogLevel(LogLevel level, char const* tag, char const* format, va_list ap); void logLevel(LogLevel level, char const* tag, char const* format, ...) __attribute__ ((format (printf, 4, 5))); void log(char const* tag, char const* format, ...) __attribute__ ((format (printf, 3, 4))); void logDebug(char const* tag, char const* format, ...) __attribute__ ((format (printf, 3, 4))); void logInfo(char const* tag, char const* format, ...) __attribute__ ((format (printf, 3, 4))); void logWarning(char const* tag, char const* format, ...) __attribute__ ((format (printf, 3, 4))); protected: LogLevel m_threshold; Log(LogLevel threshold) : m_threshold(threshold) {}; Log(Log const&) = delete; Log& operator=(Log const&) = delete; }; } repowerd-2023.07/src/core/modem_power_control.h000066400000000000000000000021031446034100200214510ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { class ModemPowerControl { public: virtual ~ModemPowerControl() = default; virtual void set_low_power_mode() = 0; virtual void set_normal_power_mode() = 0; protected: ModemPowerControl() = default; ModemPowerControl (ModemPowerControl const&) = default; ModemPowerControl& operator=(ModemPowerControl const&) = default; }; } repowerd-2023.07/src/core/notification_service.h000066400000000000000000000030251446034100200216060ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include #include #include namespace repowerd { using NotificationHandler = std::function; using NotificationDoneHandler = std::function; class NotificationService { public: virtual ~NotificationService() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_notification_handler( NotificationHandler const& handler) = 0; virtual HandlerRegistration register_notification_done_handler( NotificationDoneHandler const& handler) = 0; protected: NotificationService() = default; NotificationService (NotificationService const&) = default; NotificationService& operator=(NotificationService const&) = default; }; } repowerd-2023.07/src/core/null_state_machine.h000066400000000000000000000045101446034100200212360ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "state_machine.h" namespace repowerd { class NullStateMachine : public StateMachine { public: void handle_alarm(AlarmId) override {} void handle_active_call() override {} void handle_no_active_call() override {} void handle_enable_inactivity_timeout() override {} void handle_disable_inactivity_timeout() override {} void handle_set_inactivity_behavior( PowerAction, PowerSupply, std::chrono::milliseconds) override { } void handle_lid_closed() override {} void handle_lid_open() override {} void handle_set_lid_behavior(PowerAction, PowerSupply) override {} void handle_no_notification() override {} void handle_notification() override {} void handle_power_button_press() override {} void handle_power_button_release() override {} void handle_power_source_change() override {} void handle_power_source_critical() override {} void handle_set_critical_power_behavior(PowerAction) override {} void handle_proximity_far() override {} void handle_proximity_near() override {} void handle_user_activity_changing_power_state() override {} void handle_user_activity_extending_power_state() override {} void handle_set_normal_brightness_value(double) override {} void handle_enable_autobrightness() override {} void handle_disable_autobrightness() override {} void handle_allow_suspend(std::string id) override {(void)id;} void handle_disallow_suspend(std::string id) override {(void)id;} void handle_system_resume() override {} void start() override {} void pause() override {} void resume() override {} }; } repowerd-2023.07/src/core/performance_booster.h000066400000000000000000000021451446034100200214400ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { class PerformanceBooster { public: virtual ~PerformanceBooster() = default; virtual void enable_interactive_mode() = 0; virtual void disable_interactive_mode() = 0; protected: PerformanceBooster() = default; PerformanceBooster (PerformanceBooster const&) = default; PerformanceBooster& operator=(PerformanceBooster const&) = default; }; } repowerd-2023.07/src/core/power_action.h000066400000000000000000000014511446034100200200720ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { enum class PowerAction { none, display_off, suspend, power_off }; } repowerd-2023.07/src/core/power_button.h000066400000000000000000000024061446034100200201310ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { enum class PowerButtonState{released, pressed}; using PowerButtonHandler = std::function; class PowerButton { public: virtual ~PowerButton() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_power_button_handler( PowerButtonHandler const& handler) = 0; protected: PowerButton() = default; PowerButton (PowerButton const&) = default; PowerButton& operator=(PowerButton const&) = default; }; } repowerd-2023.07/src/core/power_button_event_sink.h000066400000000000000000000020461446034100200223560ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { class PowerButtonEventSink { public: virtual ~PowerButtonEventSink() = default; virtual void notify_long_press() = 0; protected: PowerButtonEventSink() = default; PowerButtonEventSink(PowerButtonEventSink const&) = delete; PowerButtonEventSink& operator=(PowerButtonEventSink const&) = delete; }; } repowerd-2023.07/src/core/power_source.h000066400000000000000000000027041446034100200201170ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { using PowerSourceChangeHandler = std::function; using PowerSourceCriticalHandler = std::function; class PowerSource { public: virtual ~PowerSource() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_power_source_change_handler( PowerSourceChangeHandler const& handler) = 0; virtual HandlerRegistration register_power_source_critical_handler( PowerSourceCriticalHandler const& handler) = 0; virtual bool is_using_battery_power() = 0; protected: PowerSource() = default; PowerSource (PowerSource const&) = default; PowerSource& operator=(PowerSource const&) = default; }; } repowerd-2023.07/src/core/power_supply.h000066400000000000000000000014271446034100200201540ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once namespace repowerd { enum class PowerSupply { battery, line_power }; } repowerd-2023.07/src/core/proximity_sensor.h000066400000000000000000000025711446034100200210420ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { enum class ProximityState{near, far}; using ProximityHandler = std::function; class ProximitySensor { public: virtual ~ProximitySensor() = default; virtual HandlerRegistration register_proximity_handler( ProximityHandler const& handler) = 0; virtual ProximityState proximity_state() = 0; virtual void enable_proximity_events() = 0; virtual void disable_proximity_events() = 0; protected: ProximitySensor() = default; ProximitySensor (ProximitySensor const&) = default; ProximitySensor& operator=(ProximitySensor const&) = default; }; } repowerd-2023.07/src/core/session_tracker.h000066400000000000000000000031621446034100200206000ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { enum class SessionType { RepowerdCompatible, RepowerdIncompatible }; using ActiveSessionChangedHandler = std::function; using SessionRemovedHandler = std::function; std::string const invalid_session_id; class SessionTracker { public: virtual ~SessionTracker() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_active_session_changed_handler( ActiveSessionChangedHandler const& handler) = 0; virtual HandlerRegistration register_session_removed_handler( SessionRemovedHandler const& handler) = 0; virtual std::string session_for_pid(pid_t pid) = 0; protected: SessionTracker() = default; SessionTracker (SessionTracker const&) = default; SessionTracker& operator=(SessionTracker const&) = default; }; } repowerd-2023.07/src/core/state_event_adapter.cpp000066400000000000000000000043201446034100200217530ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "state_event_adapter.h" repowerd::StateEventAdapter::StateEventAdapter(StateMachine& state_machine) : state_machine(state_machine) { } void repowerd::StateEventAdapter::handle_enable_inactivity_timeout( std::string const& request_id) { inactivity_timeout_disallowances.erase(request_id); if (inactivity_timeout_disallowances.empty()) state_machine.handle_enable_inactivity_timeout(); } void repowerd::StateEventAdapter::handle_disable_inactivity_timeout( std::string const& request_id) { inactivity_timeout_disallowances.insert(request_id); state_machine.handle_disable_inactivity_timeout(); } void repowerd::StateEventAdapter::handle_notification( std::string const& notification_id) { active_notifications.insert(notification_id); state_machine.handle_notification(); } void repowerd::StateEventAdapter::handle_notification_done( std::string const& notification_id) { auto const removed = active_notifications.erase(notification_id) == 1; if (removed && active_notifications.empty()) state_machine.handle_no_notification(); } void repowerd::StateEventAdapter::handle_allow_suspend( std::string const& request_id) { suspend_disallowances.erase(request_id); if (suspend_disallowances.empty()) state_machine.handle_allow_suspend(request_id); } void repowerd::StateEventAdapter::handle_disallow_suspend( std::string const& request_id) { suspend_disallowances.insert(request_id); state_machine.handle_disallow_suspend(request_id); } repowerd-2023.07/src/core/state_event_adapter.h000066400000000000000000000026531446034100200214270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "state_machine.h" #include #include namespace repowerd { class StateEventAdapter { public: StateEventAdapter(StateMachine& state_machine); void handle_enable_inactivity_timeout(std::string const& id); void handle_disable_inactivity_timeout(std::string const& id); void handle_notification(std::string const& id); void handle_notification_done(std::string const& id); void handle_allow_suspend(std::string const& id); void handle_disallow_suspend(std::string const& id); private: StateMachine& state_machine; std::set inactivity_timeout_disallowances; std::set active_notifications; std::set suspend_disallowances; }; } repowerd-2023.07/src/core/state_machine.h000066400000000000000000000052621446034100200202110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "alarm_id.h" #include "power_action.h" #include "power_supply.h" #include #include namespace repowerd { class StateMachine { public: virtual ~StateMachine() = default; virtual void handle_alarm(AlarmId id) = 0; virtual void handle_active_call() = 0; virtual void handle_no_active_call() = 0; virtual void handle_enable_inactivity_timeout() = 0; virtual void handle_disable_inactivity_timeout() = 0; virtual void handle_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout) = 0; virtual void handle_lid_closed() = 0; virtual void handle_lid_open() = 0; virtual void handle_set_lid_behavior( PowerAction power_action, PowerSupply power_supply) = 0; virtual void handle_no_notification() = 0; virtual void handle_notification() = 0; virtual void handle_power_button_press() = 0; virtual void handle_power_button_release() = 0; virtual void handle_power_source_change() = 0; virtual void handle_power_source_critical() = 0; virtual void handle_set_critical_power_behavior( PowerAction power_action) = 0; virtual void handle_proximity_far() = 0; virtual void handle_proximity_near() = 0; virtual void handle_user_activity_changing_power_state() = 0; virtual void handle_user_activity_extending_power_state() = 0; virtual void handle_set_normal_brightness_value(double) = 0; virtual void handle_enable_autobrightness() = 0; virtual void handle_disable_autobrightness() = 0; virtual void handle_allow_suspend(std::string) = 0; virtual void handle_disallow_suspend(std::string) = 0; virtual void handle_system_resume() = 0; virtual void start() = 0; virtual void pause() = 0; virtual void resume() = 0; protected: StateMachine() = default; StateMachine(StateMachine const&) = delete; StateMachine& operator=(StateMachine const&) = delete; }; } repowerd-2023.07/src/core/state_machine_factory.h000066400000000000000000000022131446034100200217310ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class StateMachine; class StateMachineFactory { public: virtual ~StateMachineFactory() = default; virtual std::shared_ptr create_state_machine(std::string const& name) = 0; protected: StateMachineFactory() = default; StateMachineFactory(StateMachineFactory const&) = delete; StateMachineFactory& operator=(StateMachineFactory const&) = delete; }; } repowerd-2023.07/src/core/state_machine_options.h000066400000000000000000000034331446034100200217620ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { class StateMachineOptions { public: virtual ~StateMachineOptions() = default; virtual std::chrono::milliseconds notification_expiration_timeout() const = 0; virtual std::chrono::milliseconds power_button_long_press_timeout() const = 0; virtual std::chrono::milliseconds user_inactivity_normal_display_dim_duration() const = 0; virtual std::chrono::milliseconds user_inactivity_normal_display_off_timeout() const = 0; virtual std::chrono::milliseconds user_inactivity_normal_suspend_timeout() const = 0; virtual std::chrono::milliseconds user_inactivity_post_notification_display_off_timeout() const = 0; virtual std::chrono::milliseconds user_inactivity_reduced_display_off_timeout() const = 0; virtual bool treat_power_button_as_user_activity() const = 0; virtual bool turn_on_display_at_startup() const = 0; protected: StateMachineOptions() = default; StateMachineOptions(StateMachineOptions const&) = delete; StateMachineOptions& operator=(StateMachineOptions const&) = delete; }; } repowerd-2023.07/src/core/system_power_control.h000066400000000000000000000040441446034100200217020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include #include namespace repowerd { using SystemResumeHandler = std::function; using SystemAllowSuspendHandler = std::function; using SystemDisallowSuspendHandler = std::function; class SystemPowerControl { public: virtual ~SystemPowerControl() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_system_resume_handler( SystemResumeHandler const& system_resume_handler) = 0; virtual HandlerRegistration register_system_allow_suspend_handler( SystemAllowSuspendHandler const& system_allow_suspend_handler) = 0; virtual HandlerRegistration register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const& system_disallow_suspend_handler) = 0; virtual void allow_automatic_suspend(std::string const& id) = 0; virtual void disallow_automatic_suspend(std::string const& id) = 0; virtual void power_off() = 0; virtual void suspend() = 0; virtual void allow_default_system_handlers() = 0; virtual void disallow_default_system_handlers() = 0; protected: SystemPowerControl() = default; SystemPowerControl (SystemPowerControl const&) = default; SystemPowerControl& operator=(SystemPowerControl const&) = default; }; } repowerd-2023.07/src/core/timer.h000066400000000000000000000024661446034100200165300ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include #include "alarm_id.h" #include "handler_registration.h" namespace repowerd { using AlarmHandler = std::function; class Timer { public: virtual ~Timer() = default; virtual HandlerRegistration register_alarm_handler(AlarmHandler const& handler) = 0; virtual AlarmId schedule_alarm_in(std::chrono::milliseconds t) = 0; virtual void cancel_alarm(AlarmId id) = 0; virtual std::chrono::steady_clock::time_point now() = 0; protected: Timer() = default; Timer(Timer const&) = delete; Timer& operator=(Timer const&) = delete; }; } repowerd-2023.07/src/core/user_activity.h000066400000000000000000000024421446034100200202740ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { enum class UserActivityType{change_power_state, extend_power_state}; using UserActivityHandler = std::function; class UserActivity { public: virtual ~UserActivity() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_user_activity_handler( UserActivityHandler const& handler) = 0; protected: UserActivity() = default; UserActivity(UserActivity const&) = delete; UserActivity& operator=(UserActivity const&) = delete; }; } repowerd-2023.07/src/core/voice_call_service.h000066400000000000000000000026141446034100200212230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "handler_registration.h" #include namespace repowerd { using ActiveCallHandler = std::function; using NoActiveCallHandler = std::function; class VoiceCallService { public: virtual ~VoiceCallService() = default; virtual void start_processing() = 0; virtual HandlerRegistration register_active_call_handler( ActiveCallHandler const& handler) = 0; virtual HandlerRegistration register_no_active_call_handler( NoActiveCallHandler const& handler) = 0; protected: VoiceCallService() = default; VoiceCallService (VoiceCallService const&) = default; VoiceCallService& operator=(VoiceCallService const&) = default; }; } repowerd-2023.07/src/default_daemon_config.cpp000066400000000000000000000523271446034100200213100ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "default_daemon_config.h" #include "core/default_state_machine_factory.h" #include "src/core/double_tap_to_wake.h" #include "src/core/performance_booster.h" #include "src/core/proximity_sensor.h" #include "adapters/android_autobrightness_algorithm.h" #include "adapters/android_device_config.h" #include "adapters/android_device_quirks.h" #include "adapters/backlight_brightness_control.h" #include "adapters/console_log.h" #include "adapters/default_state_machine_options.h" #include "adapters/event_loop_timer.h" #include "adapters/fs_double_tap_to_wake.h" #include "adapters/libsuspend_system_power_control.h" #include "adapters/light_sensor.h" #include "adapters/logind_session_tracker.h" #include "adapters/logind_system_power_control.h" #include "adapters/lsc_display.h" #include "adapters/lsc_power_button.h" #include "adapters/lsc_user_activity.h" #include "adapters/null_log.h" #include "adapters/ofono_voice_call_service.h" #include "adapters/real_chrono.h" #include "adapters/real_device_info.h" #include "adapters/real_filesystem.h" #include "adapters/real_temporary_suspend_inhibition.h" #include "adapters/repowerd_settings_service.h" #include "adapters/sysfs_backlight.h" #include "adapters/syslog_log.h" #include "adapters/timerfd_wakeup_service.h" #include "adapters/unity_screen_service.h" #include "adapters/upower_power_source_and_lid.h" // Hybris #ifdef REPOWERD_ENABLE_HYBRIS #include "adapters/android_backlight.h" #include "adapters/dev_alarm_wakeup_service.h" #include "adapters/ubuntu_light_sensor.h" #include "adapters/ubuntu_performance_booster.h" #include "adapters/ubuntu_proximity_sensor.h" #endif // Binder #ifdef REPOWERD_ENABLE_BINDER #include "adapters/binder_performance_booster.h" #endif // Sensorfw #include "adapters/sensorfw/sensorfw_light_sensor.h" #include "adapters/sensorfw/sensorfw_proximity_sensor.h" namespace { char const* const log_tag = "DefaultDaemonConfig"; struct NullHandlerRegistration : repowerd::HandlerRegistration { NullHandlerRegistration() : HandlerRegistration{[]{}} {} }; struct NullBrightnessControl : repowerd::BrightnessControl { void disable_autobrightness() override {} void enable_autobrightness() override {} void set_dim_brightness() override {} void set_normal_brightness() override {} void set_normal_brightness_value(double) override {} void set_off_brightness() override {} }; struct NullBrightnessNotification : repowerd::BrightnessNotification { repowerd::HandlerRegistration register_brightness_handler( repowerd::BrightnessHandler const&) override { return NullHandlerRegistration{}; } }; struct NullLightSensor : repowerd::LightSensor { repowerd::HandlerRegistration register_light_handler( repowerd::LightHandler const&) override { return NullHandlerRegistration{}; } void enable_light_events() override {} void disable_light_events() override {} }; struct NullModemPowerControl : repowerd::ModemPowerControl { void set_low_power_mode() override {} void set_normal_power_mode() override {} }; struct NullPerformanceBooster : repowerd::PerformanceBooster { void enable_interactive_mode() override {} void disable_interactive_mode() override {} }; struct NullProximitySensor : repowerd::ProximitySensor { repowerd::HandlerRegistration register_proximity_handler( repowerd::ProximityHandler const&) override { return NullHandlerRegistration{}; } repowerd::ProximityState proximity_state() override { return repowerd::ProximityState::far; } void enable_proximity_events() override {} void disable_proximity_events() override {} }; struct NullSystemPowerControl : repowerd::SystemPowerControl { void start_processing() override {} repowerd::HandlerRegistration register_system_resume_handler( repowerd::SystemResumeHandler const&) override { return NullHandlerRegistration{}; } repowerd::HandlerRegistration register_system_allow_suspend_handler( repowerd::SystemAllowSuspendHandler const&) override { return NullHandlerRegistration{}; } repowerd::HandlerRegistration register_system_disallow_suspend_handler( repowerd::SystemDisallowSuspendHandler const&) override { return NullHandlerRegistration{}; } void allow_automatic_suspend(std::string const&) override {} void disallow_automatic_suspend(std::string const&) override {} void power_off() override {} void suspend() override {} void allow_default_system_handlers() override {} void disallow_default_system_handlers() override {} }; } std::shared_ptr repowerd::DefaultDaemonConfig::the_display_information() { return the_lsc_display(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_brightness_control() { if (!brightness_control) try { brightness_control = the_backlight_brightness_control(); } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create BrightnessControl: %s", e.what()); the_log()->logWarning(log_tag, "Falling back to NullBrightnessControl"); brightness_control = std::make_shared(); } return brightness_control; } std::shared_ptr repowerd::DefaultDaemonConfig::the_client_requests() { return the_unity_screen_service(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_client_settings() { if (!client_settings) { client_settings = std::make_shared( the_log(), the_dbus_bus_address()); } return client_settings; } std::shared_ptr repowerd::DefaultDaemonConfig::the_display_power_control() { return the_lsc_display(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_display_power_event_sink() { return the_unity_screen_service(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_modem_power_control() { return the_ofono_voice_call_service(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_notification_service() { return the_unity_screen_service(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_performance_booster() { if (performance_booster) return performance_booster; #if defined(REPOWERD_ENABLE_BINDER) try { performance_booster = std::make_shared( the_log()); return performance_booster; } catch (std::exception const& e) { the_log()->log(log_tag, "Failed to create BinderPerformanceBooster: %s", e.what()); the_log()->log(log_tag, "Falling back to NullPerformanceBooster"); } #elif defined(REPOWERD_ENABLE_HYBRIS) try { performance_booster = std::make_shared( the_log()); return performance_booster; } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create UbuntuPerformanceBooster: %s", e.what()); the_log()->logWarning(log_tag, "Falling back to NullPerformanceBooster"); } #endif performance_booster = std::make_shared(); return performance_booster; } std::shared_ptr repowerd::DefaultDaemonConfig::the_power_button() { return the_lsc_power_button(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_power_button_event_sink() { return the_lsc_power_button(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_power_source() { return the_upower_power_source_and_lid(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_proximity_sensor() { if (proximity_sensor) return proximity_sensor; #ifdef REPOWERD_ENABLE_HYBRIS try { proximity_sensor = std::make_shared( the_log(), *the_device_quirks()); return proximity_sensor; } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create UbuntuProximitySensor: %s", e.what()); the_log()->logWarning(log_tag, "Trying SensorfwProximitySensor"); } #endif try { proximity_sensor = std::make_shared( the_log(), the_dbus_bus_address()); return proximity_sensor; } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create SensorfwProximitySensor: %s", e.what()); the_log()->logWarning(log_tag, "Falling back to NullProximitySensor"); } proximity_sensor = std::make_shared(); return proximity_sensor; } std::shared_ptr repowerd::DefaultDaemonConfig::the_session_tracker() { if (!session_tracker) { session_tracker = std::make_shared( the_filesystem(), the_log(), *the_device_quirks(), the_dbus_bus_address()); } return session_tracker; } std::shared_ptr repowerd::DefaultDaemonConfig::the_state_machine_factory() { if (!state_machine_factory) state_machine_factory = std::make_shared(*this); return state_machine_factory; } std::shared_ptr repowerd::DefaultDaemonConfig::the_state_machine_options() { if (!state_machine_options) state_machine_options = std::make_shared( *the_log(), the_device_info()); return state_machine_options; } std::shared_ptr repowerd::DefaultDaemonConfig::the_system_power_control() { if (!system_power_control) { try { system_power_control = std::make_shared( the_log()); } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create LibsuspendSystemPowerControl: %s", e.what()); the_log()->logWarning(log_tag, "Trying LogindSystemPowerControl"); } try { if (!system_power_control) { system_power_control = std::make_shared( the_log(), the_dbus_bus_address()); } } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create LogindSystemPowerControl: %s", e.what()); the_log()->logWarning(log_tag, "Falling back to NullSystemPowerControl"); system_power_control = std::make_shared(); } } return system_power_control; } std::shared_ptr repowerd::DefaultDaemonConfig::the_timer() { if (!timer) timer = std::make_shared(); return timer; } std::shared_ptr repowerd::DefaultDaemonConfig::the_user_activity() { if (!user_activity) user_activity = std::make_shared(the_dbus_bus_address()); return user_activity; } std::shared_ptr repowerd::DefaultDaemonConfig::the_voice_call_service() { return the_ofono_voice_call_service(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_backlight() { if (!backlight) { #ifdef REPOWERD_ENABLE_HYBRIS try { backlight = std::make_shared(); } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create AndroidBacklight: %s", e.what()); the_log()->logWarning(log_tag, "Trying SysfsBacklight"); } #endif try { if (!backlight) { backlight = std::make_shared( the_log(), the_filesystem()); } } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create SyfsBacklight: %s", e.what()); throw std::runtime_error("Failed to create backlight"); } } return backlight; } std::shared_ptr repowerd::DefaultDaemonConfig::the_backlight_brightness_control() { if (!backlight_brightness_control) { auto const ab_log_env_cstr = getenv("REPOWERD_LOG_AUTOBRIGHTNESS"); std::string const ab_log_env{ab_log_env_cstr ? ab_log_env_cstr : ""}; auto const ab_log = ab_log_env.empty() ? std::make_shared(LogLevel::Debug) : the_log(); backlight_brightness_control = std::make_shared( the_backlight(), the_light_sensor(), std::make_shared(*the_device_config(), ab_log), the_chrono(), the_log(), *the_device_config(), *the_device_quirks()); } return backlight_brightness_control; } std::shared_ptr repowerd::DefaultDaemonConfig::the_brightness_notification() { if (!brightness_notification) try { brightness_notification = the_backlight_brightness_control(); } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create BrightnessNotification: %s", e.what()); the_log()->logWarning(log_tag, "Falling back to NullBrightnessNotification"); brightness_notification = std::make_shared(); } return brightness_notification; } std::shared_ptr repowerd::DefaultDaemonConfig::the_chrono() { if (!chrono) chrono = std::make_shared(); return chrono; } std::string repowerd::DefaultDaemonConfig::the_dbus_bus_address() { auto const address = std::unique_ptr{ g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr), g_free}; return address ? address.get() : std::string{}; } std::shared_ptr repowerd::DefaultDaemonConfig::the_device_config() { if (!device_config) { auto const dir_env_cstr = getenv("REPOWERD_DEVICE_CONFIG_DIR"); std::string const dir_env{dir_env_cstr ? dir_env_cstr : ""}; std::vector device_config_dirs; if (dir_env.empty()) device_config_dirs.push_back(REPOWERD_DEVICE_CONFIG_DIR); else device_config_dirs.push_back(dir_env); device_config_dirs.push_back(POWERD_DEVICE_CONFIG_DIR); device_config = std::make_shared( the_log(), the_filesystem(), the_device_info(), device_config_dirs); } return device_config; } std::shared_ptr repowerd::DefaultDaemonConfig::the_device_quirks() { if (!device_quirks) device_quirks = std::make_shared( *the_log(), the_device_info()); return device_quirks; } std::shared_ptr repowerd::DefaultDaemonConfig::the_double_tap_to_waker() { if (!double_tap_to_wake) { double_tap_to_wake = std::make_shared(the_log(), the_filesystem()); the_log()->logDebug(log_tag, "Loaded FsDoubleTapToWake"); } return double_tap_to_wake; } std::shared_ptr repowerd::DefaultDaemonConfig::the_filesystem() { if (!filesystem) filesystem = std::make_shared(); return filesystem; } std::shared_ptr repowerd::DefaultDaemonConfig::the_light_sensor() { if (light_sensor) return light_sensor; #ifdef REPOWERD_ENABLE_HYBRIS try { light_sensor = std::make_shared(); return light_sensor; } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create UbuntuLightSensor: %s", e.what()); the_log()->logWarning(log_tag, "Trying SensorfwLightSensor"); } #endif try { light_sensor = std::make_shared( the_log(), the_dbus_bus_address()); return light_sensor; } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create SensorfwLightSensor: %s", e.what()); the_log()->logWarning(log_tag, "Falling back to NullLightSensor"); } light_sensor = std::make_shared(); return light_sensor; } std::shared_ptr repowerd::DefaultDaemonConfig::the_ofono_voice_call_service() { if (!ofono_voice_call_service) { ofono_voice_call_service = std::make_shared( the_log(), the_dbus_bus_address()); } return ofono_voice_call_service; } std::shared_ptr repowerd::DefaultDaemonConfig::the_lid() { return the_upower_power_source_and_lid(); } std::shared_ptr repowerd::DefaultDaemonConfig::the_temporary_suspend_inhibition() { if (!temporary_suspend_inhibition) { temporary_suspend_inhibition = std::make_shared( the_system_power_control()); } return temporary_suspend_inhibition; } std::shared_ptr repowerd::DefaultDaemonConfig::the_log() { if (!log) { auto const log_threshold_cstr = getenv("REPOWERD_LOG_LEVEL"); std::string const log_threshold_str{log_threshold_cstr ? log_threshold_cstr : ""}; repowerd::LogLevel log_threshold{LogLevel::Info}; if (log_threshold_str == "debug") log_threshold = LogLevel::Debug; else if (log_threshold_str == "info") log_threshold = LogLevel::Info; else if (log_threshold_str == "info") log_threshold = LogLevel::Warning; auto const log_env_cstr = getenv("REPOWERD_LOG"); std::string const log_env{log_env_cstr ? log_env_cstr : ""}; if (log_env == "console") log = std::make_shared(log_threshold); else if (log_env == "null") log = std::make_shared(log_threshold); else log = std::make_shared(log_threshold); } return log; } std::shared_ptr repowerd::DefaultDaemonConfig::the_lsc_display() { if (!lsc_display) { lsc_display = std::make_shared( the_log(), the_dbus_bus_address()); } return lsc_display; } std::shared_ptr repowerd::DefaultDaemonConfig::the_unity_screen_service() { if (!unity_screen_service) { unity_screen_service = std::make_shared( the_wakeup_service(), the_brightness_notification(), the_log(), the_temporary_suspend_inhibition(), the_double_tap_to_waker(), *the_device_config(), the_dbus_bus_address()); } return unity_screen_service; } std::shared_ptr repowerd::DefaultDaemonConfig::the_lsc_power_button() { if (!lsc_power_button) lsc_power_button = std::make_shared(the_dbus_bus_address()); return lsc_power_button; } std::shared_ptr repowerd::DefaultDaemonConfig::the_upower_power_source_and_lid() { if (!upower_power_source_and_lid) { upower_power_source_and_lid = std::make_shared( the_log(), the_temporary_suspend_inhibition(), *the_device_config(), the_dbus_bus_address()); } return upower_power_source_and_lid; } std::shared_ptr repowerd::DefaultDaemonConfig::the_wakeup_service() { #ifdef REPOWERD_ENABLE_HYBRIS if (!wakeup_service) try { wakeup_service = std::make_shared(the_filesystem()); } catch (std::exception const& e) { the_log()->logWarning(log_tag, "Failed to create DevAlarmWakeupService: %s", e.what()); the_log()->logWarning(log_tag, "Trying TimerfdWakeupService"); } #endif if (!wakeup_service) wakeup_service = std::make_shared(the_log()); return wakeup_service; } std::shared_ptr repowerd::DefaultDaemonConfig::the_device_info() { if (!device_info) device_info = std::make_shared(); return device_info; } repowerd-2023.07/src/default_daemon_config.h000066400000000000000000000126231446034100200207500ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "core/daemon_config.h" namespace repowerd { class Backlight; class BacklightBrightnessControl; class BrightnessNotification; class Chrono; class DeviceConfig; class DeviceQuirks; class DoubleTapToWake; class Filesystem; class LightSensor; class LscDisplay; class LscPowerButton; class OfonoVoiceCallService; class TemporarySuspendInhibition; class UnityScreenService; class UPowerPowerSourceAndLid; class WakeupService; class DeviceInfo; class DefaultDaemonConfig : public DaemonConfig { public: std::shared_ptr the_display_information() override; std::shared_ptr the_brightness_control() override; std::shared_ptr the_client_requests() override; std::shared_ptr the_client_settings() override; std::shared_ptr the_display_power_control() override; std::shared_ptr the_display_power_event_sink() override; std::shared_ptr the_lid() override; std::shared_ptr the_log() override; std::shared_ptr the_modem_power_control() override; std::shared_ptr the_notification_service() override; std::shared_ptr the_performance_booster() override; std::shared_ptr the_power_button() override; std::shared_ptr the_power_button_event_sink() override; std::shared_ptr the_power_source() override; std::shared_ptr the_proximity_sensor() override; std::shared_ptr the_session_tracker() override; std::shared_ptr the_state_machine_factory() override; std::shared_ptr the_state_machine_options() override; std::shared_ptr the_system_power_control() override; std::shared_ptr the_timer() override; std::shared_ptr the_user_activity() override; std::shared_ptr the_voice_call_service() override; std::shared_ptr the_backlight(); std::shared_ptr the_backlight_brightness_control(); std::shared_ptr the_brightness_notification(); std::shared_ptr the_chrono(); std::string the_dbus_bus_address(); std::shared_ptr the_device_config(); std::shared_ptr the_device_quirks(); std::shared_ptr the_double_tap_to_waker(); std::shared_ptr the_filesystem(); std::shared_ptr the_light_sensor(); std::shared_ptr the_lsc_display(); std::shared_ptr the_lsc_power_button(); std::shared_ptr the_ofono_voice_call_service(); std::shared_ptr the_temporary_suspend_inhibition(); std::shared_ptr the_unity_screen_service(); std::shared_ptr the_upower_power_source_and_lid(); std::shared_ptr the_wakeup_service(); std::shared_ptr the_device_info(); private: std::shared_ptr display_information; std::shared_ptr backlight; std::shared_ptr backlight_brightness_control; std::shared_ptr brightness_control; std::shared_ptr brightness_notification; std::shared_ptr chrono; std::shared_ptr client_settings; std::shared_ptr device_config; std::shared_ptr device_quirks; std::shared_ptr double_tap_to_wake; std::shared_ptr filesystem; std::shared_ptr light_sensor; std::shared_ptr lsc_display; std::shared_ptr lsc_power_button; std::shared_ptr log; std::shared_ptr modem_power_control; std::shared_ptr ofono_voice_call_service; std::shared_ptr performance_booster; std::shared_ptr proximity_sensor; std::shared_ptr session_tracker; std::shared_ptr state_machine_factory; std::shared_ptr state_machine_options; std::shared_ptr system_power_control; std::shared_ptr timer; std::shared_ptr temporary_suspend_inhibition; std::shared_ptr unity_screen_service; std::shared_ptr upower_power_source_and_lid; std::shared_ptr user_activity; std::shared_ptr wakeup_service; std::shared_ptr device_info; }; } repowerd-2023.07/src/main.cpp000066400000000000000000000043061446034100200157320ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "core/daemon.h" #include "core/log.h" #include "default_daemon_config.h" #include #include namespace { char const* const log_tag = "main"; struct SignalHandler { SignalHandler(repowerd::Daemon* daemon_ptr, repowerd::Log* log_ptr) { SignalHandler::daemon_ptr = daemon_ptr; SignalHandler::log_ptr = log_ptr; struct sigaction new_action; new_action.sa_handler = stop_daemon; new_action.sa_flags = 0; sigfillset(&new_action.sa_mask); sigaction(SIGINT, &new_action, &old_sigint_action); sigaction(SIGTERM, &new_action, &old_sigterm_action); } ~SignalHandler() { sigaction(SIGINT, &old_sigint_action, nullptr); sigaction(SIGTERM, &old_sigterm_action, nullptr); } static void stop_daemon(int sig) { log_ptr->logInfo(log_tag, "Received signal %s", strsignal(sig)); daemon_ptr->stop(); } static repowerd::Daemon* daemon_ptr; static repowerd::Log* log_ptr; struct sigaction old_sigint_action; struct sigaction old_sigterm_action; }; repowerd::Daemon* SignalHandler::daemon_ptr{nullptr}; repowerd::Log* SignalHandler::log_ptr{nullptr}; } int main() { repowerd::DefaultDaemonConfig config; auto const log = config.the_log(); log->logInfo(log_tag, "Starting repowerd %s", REPOWERD_VERSION); repowerd::Daemon daemon{config}; SignalHandler signal_handler{&daemon, log.get()}; daemon.run(); log->logInfo(log_tag, "Exiting repowerd"); } repowerd-2023.07/src/tools/000077500000000000000000000000001446034100200154375ustar00rootroot00000000000000repowerd-2023.07/src/tools/CMakeLists.txt000066400000000000000000000042711446034100200202030ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis add_executable( repowerd-brightness-tool brightness_tool.cpp ) target_link_libraries( repowerd-brightness-tool repowerd-core repowerd-adapters repowerd-default-daemon-config ) add_executable( repowerd-cli cli.cpp ) target_link_libraries( repowerd-cli repowerd-core repowerd-adapters ) add_executable( repowerd-light-tool light_tool.cpp ) target_link_libraries( repowerd-light-tool repowerd-core repowerd-adapters repowerd-default-daemon-config ) add_executable( repowerd-power-source-tool power_source_tool.cpp ../default_daemon_config.cpp ) target_link_libraries( repowerd-power-source-tool repowerd-core repowerd-adapters repowerd-default-daemon-config ) add_executable( repowerd-proximity-tool proximity_tool.cpp ) target_link_libraries( repowerd-proximity-tool repowerd-core repowerd-adapters repowerd-default-daemon-config ) add_executable( repowerd-session-tool session_tool.cpp ) target_link_libraries( repowerd-session-tool repowerd-core repowerd-adapters repowerd-default-daemon-config ) add_executable( repowerd-wakeup-tool wakeup_tool.cpp ) target_link_libraries( repowerd-wakeup-tool repowerd-core repowerd-adapters repowerd-default-daemon-config ) install( TARGETS repowerd-brightness-tool repowerd-cli repowerd-light-tool repowerd-proximity-tool repowerd-wakeup-tool RUNTIME DESTINATION sbin ) repowerd-2023.07/src/tools/brightness_tool.cpp000066400000000000000000000057521446034100200213610ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/default_daemon_config.h" #include "src/core/brightness_control.h" #include #include #include int main() { setenv("REPOWERD_LOG", "console", 1); repowerd::DefaultDaemonConfig config; auto const brightness_control = config.the_brightness_control(); bool running = true; std::cout << "Commands (press enter after command letter): "<< std::endl << " d => dim brightness" << std::endl << " n => normal brightness" << std::endl << " o => off brightness" << std::endl << " ae => autobrightness enable" << std::endl << " ad => autobrightness disable" << std::endl << " 1-9,0 => set normal brightness value 10%-90%,100%" << std::endl << " q => quit" << std::endl; while (running) { std::string line; std::getline(std::cin, line); if (line == "q") { running = false; } else if (line == "d") { std::cout << "Setting dim brightness" << std::endl; brightness_control->set_dim_brightness(); } else if (line == "n") { std::cout << "Setting normal brightness" << std::endl; brightness_control->set_normal_brightness(); } else if (line == "o") { std::cout << "Setting off brightness" << std::endl; brightness_control->set_off_brightness(); } else if (line == "ae") { std::cout << "Enabling autobrightness" << std::endl; brightness_control->enable_autobrightness(); } else if (line == "ad") { std::cout << "Disabling autobrightness" << std::endl; brightness_control->disable_autobrightness(); } else if (line == "0") { std::cout << "Setting normal brightness value to 100%" << std::endl; brightness_control->set_normal_brightness_value(1.0); } else if (line.size() == 1 && line[0] >= '1' && line[0] <= '9') { auto b = line[0] - '0'; std::cout << "Setting normal brightness value to " << b*10 << "%" << std::endl; brightness_control->set_normal_brightness_value(0.1*b); } } } repowerd-2023.07/src/tools/cli.cpp000066400000000000000000000430031446034100200167120ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/scoped_g_error.h" #include #include #include #include #include #include std::string get_progname(int argc, char** argv) { if (argc == 0) return ""; else return argv[0]; } std::vector get_args(int argc, char** argv) { std::vector args; for (int i = 1; i < argc; ++i) args.push_back(argv[i]); return args; } void show_usage(std::string const& progname) { std::cerr << "Usage: " << progname << " " << std::endl; std::cerr << "Available commands: " << std::endl; std::cerr << " display [on]: keep display on until program is terminated" << std::endl; std::cerr << " active: inhibit device suspend until program is terminated" << std::endl; std::cerr << " listsysrequests: list external suspend inhibitors" << std::endl; std::cerr << " get double-tap-to-wake-enabled" << std::endl; std::cerr << " get double-tap-to-wake-supported" << std::endl; std::cerr << " set double-tap-to-wake-enabled " << std::endl; std::cerr << " settings inactivity " << std::endl; std::cerr << " settings lid " << std::endl; std::cerr << " settings critical-power " << std::endl; std::cerr << std::endl; std::cerr << ": none, display-off, suspend, power-off" << std::endl; std::cerr << ": battery, line-power" << std::endl; } std::unique_ptr create_unity_screen_proxy() { repowerd::ScopedGError error; auto uscreen_proxy = g_dbus_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "com.canonical.Unity.Screen", "/com/canonical/Unity/Screen", "com.canonical.Unity.Screen", NULL, error); if (uscreen_proxy == nullptr) { throw std::runtime_error( "Failed to connect to com.canonical.Unity.Screen: " + error.message_str()); } return {uscreen_proxy, g_object_unref}; } std::unique_ptr create_repowerd_proxy() { repowerd::ScopedGError error; auto repowerd_proxy = g_dbus_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "com.lomiri.Repowerd", "/com/lomiri/Repowerd", "com.lomiri.Repowerd", NULL, error); if (repowerd_proxy == nullptr) { throw std::runtime_error( "Failed to connect to com.lomiri.Repowerd: " + error.message_str()); } return {repowerd_proxy, g_object_unref}; } std::unique_ptr create_repowerd_settings_proxy() { repowerd::ScopedGError error; auto repowerd_settings_proxy = g_dbus_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "com.lomiri.Repowerd.Settings", "/com/lomiri/Repowerd/Settings", "com.lomiri.Repowerd.Settings", NULL, error); if (repowerd_settings_proxy == nullptr) { throw std::runtime_error( "Failed to connect to com.lomiri.Repowerd.Settings: " + error.message_str()); } return {repowerd_settings_proxy, g_object_unref}; } int32_t keep_display_on(GDBusProxy* uscreen_proxy) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( uscreen_proxy, "keepDisplayOn", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.canonical.Unity.Screen.keepDisplayOn() failed: " + error.message_str()); } int32_t cookie{0}; g_variant_get(ret, "(i)", &cookie); g_variant_unref(ret); return cookie; } void remove_display_on_request(GDBusProxy* uscreen_proxy, int32_t cookie) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( uscreen_proxy, "removeDisplayOnRequest", g_variant_new("(i)", cookie), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.canonical.Unity.Screen.removeDisplayOnRequest() failed: " + error.message_str()); } g_variant_unref(ret); } std::string request_sys_state_active(GDBusProxy* repowerd_proxy) { static int constexpr active_state = 1; repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( repowerd_proxy, "requestSysState", g_variant_new("(si)", "repowerd-cli", active_state), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.lomiri.Repowerd.requestSysState(active) failed: " + error.message_str()); } char const* cookie_raw{""}; g_variant_get(ret, "(&s)", &cookie_raw); std::string cookie{cookie_raw}; g_variant_unref(ret); return cookie; } void clear_sys_state(GDBusProxy* repowerd_proxy, std::string const& cookie) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( repowerd_proxy, "clearSysState", g_variant_new("(s)", cookie.c_str()), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.lomiri.Repowerd.clearSysState() failed: " + error.message_str()); } g_variant_unref(ret); } void set_inactivity_behavior( GDBusProxy* repowerd_settings_proxy, std::string const& action, std::string const& supply, int32_t timeout) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( repowerd_settings_proxy, "SetInactivityBehavior", g_variant_new("(ssi)", action.c_str(), supply.c_str(), timeout), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.lomiri.Repowerd.Settings.SetInactivityBehavior() failed: " + error.message_str()); } g_variant_unref(ret); } void set_lid_behavior( GDBusProxy* repowerd_settings_proxy, std::string const& action, std::string const& supply) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( repowerd_settings_proxy, "SetLidBehavior", g_variant_new("(ss)", action.c_str(), supply.c_str()), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.lomiri.Repowerd.Settings.SetLidBehavior() failed: " + error.message_str()); } g_variant_unref(ret); } void set_critical_power_behavior( GDBusProxy* repowerd_settings_proxy, std::string const& action) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( repowerd_settings_proxy, "SetCriticalPowerBehavior", g_variant_new("(s)", action.c_str()), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.lomiri.Repowerd.Settings.SetCriticalPowerBehavior() failed: " + error.message_str()); } g_variant_unref(ret); } bool get_double_tap_to_wake_enabled(GDBusProxy* uscreen_proxy) { repowerd::ScopedGError error; gboolean enabled = FALSE; auto ret = g_dbus_proxy_call_sync( uscreen_proxy, "getDoubleTapToWakeEnabled", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.canonical.Unity.Screen.getDoubleTapToWakeEnabled() failed: " + error.message_str()); } ret = g_variant_get_child_value(ret, 0); enabled = g_variant_get_boolean(ret); g_variant_unref(ret); return enabled == TRUE; } bool get_double_tap_to_wake_supported(GDBusProxy* uscreen_proxy) { repowerd::ScopedGError error; gboolean enabled = FALSE; auto ret = g_dbus_proxy_call_sync( uscreen_proxy, "getDoubleTapToWakeSupported", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.canonical.Unity.Screen.getDoubleTapToWakeSupported() failed: " + error.message_str()); } ret = g_variant_get_child_value(ret, 0); enabled = g_variant_get_boolean(ret); g_variant_unref(ret); return enabled == TRUE; } void set_double_tap_to_wake_enabled( GDBusProxy* uscreen_proxy, bool const enable) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( uscreen_proxy, "setDoubleTapToWakeEnabled", g_variant_new("(b)", enable), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.canonical.Unity.Screen.setDoubleTapToWakeEnabled() failed: " + error.message_str()); } g_variant_unref(ret); } void handle_display_command(GDBusProxy* uscreen_proxy) { auto const cookie = keep_display_on(uscreen_proxy); std::cout << "keepDisplayOn requested, cookie is " << cookie << std::endl; std::cout << "Press ctrl-c to exit" << std::endl; pause(); remove_display_on_request(uscreen_proxy, cookie); } void handle_active_command(GDBusProxy* uscreen_proxy) { auto const cookie = request_sys_state_active(uscreen_proxy); std::cout << "requestSysState(active) requested, cookie is " << cookie << std::endl; std::cout << "Press ctrl-c to exit" << std::endl; pause(); clear_sys_state(uscreen_proxy, cookie); } void handle_listsysrequests_command(GDBusProxy* repowerd_proxy) { repowerd::ScopedGError error; auto const ret = g_dbus_proxy_call_sync( repowerd_proxy, "listSysRequests", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (ret == nullptr) { throw std::runtime_error( "com.lomiri.Repowerd.listSysRequests() failed: " + error.message_str()); } auto dict = g_variant_get_child_value(ret, 0); auto dict_size = g_variant_n_children(dict); for(gsize i = 0; i < dict_size; i++){ auto dict_entry = g_variant_get_child_value(dict, i); auto dict_key = g_variant_get_child_value(dict_entry, 0); auto dict_value_boxed = g_variant_get_child_value(dict_entry, 1); auto dict_value = g_variant_get_child_value(dict_value_boxed, 0); auto dict_key_str = std::string(g_variant_get_string(dict_key, NULL)); if(dict_key_str == "request_sys_state"){ std::cout << "Listing currently active sys requests (suspend block request):" << std::endl; auto list_size = g_variant_n_children(dict_value); for(gsize j = 0;j < list_size; j++){ auto child = g_variant_get_child_value(dict_value, j); char const* sender; int32_t id; uint64_t pid; char const* name; g_variant_get(child, "(&sit&s)", &sender, &id, &pid, &name); std::cout << "sender: " << sender; std::cout << " | sender pid: " << pid; std::cout << " | id/cookie: " << id; std::cout << " | name: " << name << std::endl; g_variant_unref(child); } std::cout << std::endl; }else if (dict_key_str == "keep_display_on"){ std::cout << "Listing currently active keep display on requests:" << std::endl; auto list_size = g_variant_n_children(dict_value); for(gsize j = 0;j < list_size; j++){ auto child = g_variant_get_child_value(dict_value, j); char const* sender; int32_t id; uint64_t pid; g_variant_get(child, "(&sit)", &sender, &id, &pid); std::cout << "sender: " << sender; std::cout << " | sender pid: " << pid; std::cout << " | id/cookie: " << id << std::endl; g_variant_unref(child); } std::cout << std::endl; }else if (dict_key_str == "active_notifications"){ std::cout << "Listing currently active notification requests:" << std::endl; auto list_size = g_variant_n_children(dict_value); for(gsize j = 0;j < list_size; j++){ auto child = g_variant_get_child_value(dict_value, j); char const* sender; uint64_t pid; int32_t reason; g_variant_get(child, "(&sti)", &sender, &pid, &reason); std::cout << "sender: " << sender; std::cout << " | sender pid: " << pid; std::cout << " | reason: " << reason << std::endl; g_variant_unref(child); } std::cout << std::endl; }else{ std::cout << "Unknown dictionary key " << dict_key_str << std::endl << std::endl; } g_variant_unref(dict_key); g_variant_unref(dict_value); g_variant_unref(dict_value_boxed); g_variant_unref(dict_entry); } g_variant_unref(dict); g_variant_unref(ret); } void handle_set_command( GDBusProxy* uscreen_proxy, std::vector const& args) { if (args.size() < 2) throw std::invalid_argument{""}; if (args[1] == "double-tap-to-wake-enabled") { if (args.size() != 3) throw std::invalid_argument{""}; auto const enable = (args[2] == "true" || args[2] == "1"); set_double_tap_to_wake_enabled(uscreen_proxy, enable); } else { throw std::invalid_argument{""}; } } void handle_get_command( GDBusProxy* uscreen_proxy, std::vector const& args) { if (args.size() < 2) throw std::invalid_argument{""}; if (args[1] == "double-tap-to-wake-enabled") { auto enabled = get_double_tap_to_wake_enabled(uscreen_proxy); std::cerr << "double-tap-to-wake-enabled: "<< (enabled ? "true" : "false") << std::endl; } else if (args[1] == "double-tap-to-wake-supported") { auto supported = get_double_tap_to_wake_supported(uscreen_proxy); std::cerr << "double-tap-to-wake-supported: "<< (supported ? "true" : "false") << std::endl; } else { throw std::invalid_argument{""}; } } void handle_settings_command( GDBusProxy* repowerd_settings_proxy, std::vector const& args) { if (args.size() < 2) throw std::invalid_argument{""}; if (args[1] == "inactivity") { if (args.size() != 5) throw std::invalid_argument{""}; auto const& action = args[2]; auto const& supply = args[3]; auto const timeout = std::stoi(args[4]); set_inactivity_behavior(repowerd_settings_proxy, action, supply, timeout); } else if (args[1] == "lid") { if (args.size() != 4) throw std::invalid_argument{""}; auto const& action = args[2]; auto const& supply = args[3]; set_lid_behavior(repowerd_settings_proxy, action, supply); } else if (args[1] == "critical-power") { if (args.size() != 3) throw std::invalid_argument{""}; auto const& action = args[2]; set_critical_power_behavior(repowerd_settings_proxy, action); } else { throw std::invalid_argument{""}; } } void null_signal_handler(int) {} int main(int argc, char** argv) try { signal(SIGINT, null_signal_handler); signal(SIGTERM, null_signal_handler); auto const args = get_args(argc, argv); if (args.size() == 0) throw std::invalid_argument{""}; auto const uscreen_proxy = create_unity_screen_proxy(); auto const repowerd_proxy = create_repowerd_proxy(); auto const repowerd_settings_proxy = create_repowerd_settings_proxy(); if (args[0] == "display") { handle_display_command(uscreen_proxy.get()); } else if (args[0] == "active") { handle_active_command(repowerd_proxy.get()); } else if (args[0] == "listsysrequests") { handle_listsysrequests_command(repowerd_proxy.get()); } else if (args[0] == "settings") { handle_settings_command(repowerd_settings_proxy.get(), args); } else if (args[0] == "get") { handle_get_command(uscreen_proxy.get(), args); } else if (args[0] == "set") { handle_set_command(uscreen_proxy.get(), args); } else { throw std::invalid_argument{""}; } } catch (std::invalid_argument const& e) { show_usage(get_progname(argc, argv)); return -1; } catch (std::exception const& e) { std::cerr << e.what() << std::endl; return -1; } repowerd-2023.07/src/tools/light_tool.cpp000066400000000000000000000036151446034100200203140ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/default_daemon_config.h" #include "src/adapters/light_sensor.h" #include #include #include int main() { setenv("REPOWERD_LOG", "console", 1); repowerd::DefaultDaemonConfig config; auto const light_sensor = config.the_light_sensor(); auto registration = light_sensor->register_light_handler( [] (double light) { std::cout << "LIGHT: " << light << std::endl; }); bool running = true; std::cout << "Commands (press enter after command letter): "<< std::endl << " e => enable light events" << std::endl << " d => disable light events" << std::endl << " q => quit" << std::endl; while (running) { std::string line; std::getline(std::cin, line); if (line == "q") { running = false; } else if (line == "d") { std::cout << "Disabling light events" << std::endl; light_sensor->disable_light_events(); } else if (line == "e") { std::cout << "Enabling light events" << std::endl; light_sensor->enable_light_events(); } } } repowerd-2023.07/src/tools/power_source_tool.cpp000066400000000000000000000027661446034100200217270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/default_daemon_config.h" #include "src/core/power_source.h" #include #include #include int main() { setenv("REPOWERD_LOG", "console", 1); repowerd::DefaultDaemonConfig config; auto const power_source = config.the_power_source(); power_source->start_processing(); auto registration = power_source->register_power_source_change_handler( [] { std::cout << "Power source changed" << std::endl; }); bool running = true; std::cout << "Commands (press enter after command letter): "<< std::endl << " q => quit" << std::endl; while (running) { std::string line; std::getline(std::cin, line); if (line == "q") { running = false; } } } repowerd-2023.07/src/tools/proximity_tool.cpp000066400000000000000000000045511446034100200212510ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/default_daemon_config.h" #include "src/core/proximity_sensor.h" #include #include #include void print_proximity(std::string const& s, repowerd::ProximityState state) { if (state == repowerd::ProximityState::near) std::cout << s << "near" << std::endl; else std::cout << s << "far" << std::endl; } int main() { setenv("REPOWERD_LOG", "console", 1); repowerd::DefaultDaemonConfig config; auto const proximity_sensor = config.the_proximity_sensor(); auto registration = proximity_sensor->register_proximity_handler( [] (repowerd::ProximityState state) { print_proximity("EVENT: ", state); }); bool running = true; std::cout << "Commands (press enter after command letter): "<< std::endl << " e => enable proximity events" << std::endl << " d => disable proximity events" << std::endl << " s => display proximity state" << std::endl << " q => quit" << std::endl; while (running) { std::string line; std::getline(std::cin, line); if (line == "q") { running = false; } else if (line == "d") { std::cout << "Disabling proximity events" << std::endl; proximity_sensor->disable_proximity_events(); } else if (line == "e") { std::cout << "Enabling proximity events" << std::endl; proximity_sensor->enable_proximity_events(); } else if (line == "s") { print_proximity("STATE: ", proximity_sensor->proximity_state()); } } } repowerd-2023.07/src/tools/session_tool.cpp000066400000000000000000000034101446034100200206610ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/default_daemon_config.h" #include "src/core/session_tracker.h" #include #include #include #include int main() { setenv("REPOWERD_LOG", "console", 1); repowerd::DefaultDaemonConfig config; auto const session_tracker = config.the_session_tracker(); auto const active_reg = session_tracker->register_active_session_changed_handler( [] (std::string const& session_id, repowerd::SessionType type) { auto const compatibility_cstr = (type == repowerd::SessionType::RepowerdCompatible) ? "compatible" : "incompatible"; std::cout << "ACTIVE SESSION: " << session_id << " (" << compatibility_cstr << " with repowerd)" << std::endl; }); auto const remove_reg = session_tracker->register_session_removed_handler( [] (std::string const& session_id) { std::cout << "SESSION REMOVED: " << session_id << std::endl; }); session_tracker->start_processing(); pause(); } repowerd-2023.07/src/tools/wakeup_tool.cpp000066400000000000000000000047741446034100200205100ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/default_daemon_config.h" #include "src/adapters/wakeup_service.h" #include #include #include #include #include std::vector parse_wakeups(int argc, char** argv) { std::vector wakeups; for (auto i = 1; i < argc; ++i) { wakeups.push_back(std::stoi(argv[i])); } return wakeups; } void print_wakeups(std::vector const& wakeups) { std::cout << "Wakeups @ "; for (auto const& w : wakeups) std::cout << w << " "; std::cout << std::endl; } void print_wakeup_event(std::string const& cookie) { std::cout << "Wakeup with cookie '" << cookie << "'" << std::endl; } void print_usage(std::string const& progname) { std::cout << "Usage: " << progname << " " << std::endl; std::cout << "Schedules and waits for hardware wakeups" << std::endl; std::cout << "Example: " << progname << " 1 3 5" << std::endl; } int main(int argc, char** argv) { setenv("REPOWERD_LOG", "console", 1); repowerd::DefaultDaemonConfig config; auto const wakeup_service = config.the_wakeup_service(); auto const wakeups = parse_wakeups(argc, argv); if (wakeups.empty()) { print_usage(argv[0]); return 1; } print_wakeups(wakeups); std::promise done; auto done_future = done.get_future(); auto wakeup_count = 0u; auto registration = wakeup_service->register_wakeup_handler( [&] (std::string const& cookie) { print_wakeup_event(cookie); if (++wakeup_count == wakeups.size()) done.set_value(); }); for (auto const& w : wakeups) { wakeup_service->schedule_wakeup_at( std::chrono::system_clock::now() + std::chrono::seconds{w}); } done_future.get(); } repowerd-2023.07/tests/000077500000000000000000000000001446034100200146525ustar00rootroot00000000000000repowerd-2023.07/tests/CMakeLists.txt000066400000000000000000000015571446034100200174220ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis include_directories( ${CMAKE_SOURCE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} common ) add_subdirectory(adapter-tests/) add_subdirectory(core-tests/) add_subdirectory(common/) repowerd-2023.07/tests/adapter-tests/000077500000000000000000000000001446034100200174325ustar00rootroot00000000000000repowerd-2023.07/tests/adapter-tests/CMakeLists.txt000066400000000000000000000061271446034100200222000ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis if (REPOWERD_ENABLE_HYBRIS) set(REPOWERD_ADAPTER_TEST_HYBRIS_SRCS fake_libhardware.cpp test_android_backlight.cpp test_dev_alarm_wakeup_service.cpp test_ubuntu_light_sensor.cpp test_ubuntu_proximity_sensor.cpp ) endif() add_executable( repowerd-adapter-tests current_thread_name.cpp dbus_bus.cpp dbus_client.cpp fake_device_info.cpp fake_brightness_notification.cpp fake_chrono.cpp fake_device_config.cpp fake_device_quirks.cpp fake_double_tap_to_wake.cpp fake_filesystem.cpp fake_logind.cpp fake_ofono.cpp fake_upower.cpp fake_wakeup_service.cpp repowerd_settings_dbus_client.cpp run_command.cpp temporary_environment_value.cpp temporary_file.cpp unity_screen_dbus_client.cpp test_android_autobrightness_algorithm.cpp test_android_device_config.cpp test_android_device_quirks.cpp test_backlight_brightness_control.cpp test_brightness_params.cpp test_dbus_event_loop.cpp test_default_state_machine_options.cpp test_event_loop.cpp test_event_loop_timer.cpp test_fd.cpp test_logind_session_tracker.cpp test_logind_system_power_control.cpp test_lsc_display.cpp test_lsc_power_button.cpp test_lsc_user_activity.cpp test_monotone_spline.cpp test_ofono_voice_call_service.cpp test_path.cpp test_real_chrono.cpp test_real_filesystem.cpp test_real_temporary_suspend_inhibition.cpp test_repowerd_service.cpp test_repowerd_settings_service.cpp test_sysfs_backlight.cpp test_timerfd_wakeup_service.cpp test_unique_random_pool.cpp test_unity_screen_service.cpp test_upower_power_source_and_lid.cpp ${REPOWERD_ADAPTER_TEST_HYBRIS_SRCS} ) target_link_libraries( repowerd-adapter-tests repowerd-core repowerd-adapters repowerd-test-common ${GTEST_LIBRARY} ${GMOCK_LIBRARIES} ) if (REPOWERD_DISABLE_TIME_SENSITIVE_TESTS) set( ADAPTER_TESTS_FILTER "${ADAPTER_TESTS_FILTER}:\ ARealChrono.*:\ AnEventLoopTimer.*:\ ARealTemporarySuspendInhibition.*:\ ATimerfdWakeupService.*:\ AnLscDisplay.waits_at_most_one_second_for_turn_on_response" ) string(REPLACE " " "" ADAPTER_TESTS_FILTER ${ADAPTER_TESTS_FILTER}) endif() add_test( repowerd-adapter-tests ${EXECUTABLE_OUTPUT_PATH}/repowerd-adapter-tests --gtest_filter=-${ADAPTER_TESTS_FILTER} ) repowerd-2023.07/tests/adapter-tests/current_thread_name.cpp000066400000000000000000000017641446034100200241570ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "current_thread_name.h" #include std::string repowerd::test::current_thread_name() { static size_t constexpr max_thread_name_size = 16; char thread_name[max_thread_name_size]; pthread_getname_np(pthread_self(), thread_name, sizeof thread_name); return {thread_name}; } repowerd-2023.07/tests/adapter-tests/current_thread_name.h000066400000000000000000000014601446034100200236150ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { namespace test { std::string current_thread_name(); } } repowerd-2023.07/tests/adapter-tests/dbus_bus.cpp000066400000000000000000000025261446034100200217510ustar00rootroot00000000000000/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "run_command.h" #include #include #include namespace rt = repowerd::test; rt::DBusBus::DBusBus() : pid{0} { auto launch = rt::run_command( "dbus-daemon --session --print-address=1 --print-pid=1 --fork"); std::stringstream ss{launch}; std::getline(ss, address_); ss >> pid; if (address_.empty()) throw std::runtime_error("Failed to get dbus bus address"); if (pid == 0) throw std::runtime_error("Failed to get dbus bus pid"); } rt::DBusBus::~DBusBus() { kill(pid, SIGTERM); } std::string rt::DBusBus::address() { return address_; } repowerd-2023.07/tests/adapter-tests/dbus_bus.h000066400000000000000000000016551446034100200214200ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { namespace test { class DBusBus { public: DBusBus(); ~DBusBus(); std::string address(); private: std::string address_; pid_t pid; }; } } repowerd-2023.07/tests/adapter-tests/dbus_client.cpp000066400000000000000000000125271446034100200224400ustar00rootroot00000000000000/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_client.h" #include "src/adapters/dbus_message_handle.h" #include "src/adapters/scoped_g_error.h" #include namespace rt = repowerd::test; rt::DBusAsyncReply::DBusAsyncReply(DBusAsyncReply&& other) : promise{std::move(other.promise)} { } rt::DBusAsyncReply::~DBusAsyncReply() { throw_on_error_reply(get()); } repowerd::DBusMessageHandle rt::DBusAsyncReply::get() { if (pending) { auto future = promise.get_future(); pending = false; return repowerd::DBusMessageHandle{future.get()}; } else { return repowerd::DBusMessageHandle{nullptr}; } } void rt::DBusAsyncReply::set_pending() { pending = true; } void rt::DBusAsyncReply::static_set_async_result( GDBusConnection* connection, GAsyncResult* result, DBusAsyncReply* reply) { auto const msg = g_dbus_connection_send_message_with_reply_finish( connection, result, nullptr); reply->set_async_result(msg); } void rt::DBusAsyncReply::throw_on_error_reply(GDBusMessage* reply) { if (reply && g_dbus_message_get_error_name(reply) != nullptr) { ScopedGError error; g_dbus_message_to_gerror(reply, error); throw std::runtime_error("Got an error reply: " + error.message_str()); } } void rt::DBusAsyncReply::throw_on_invalid_reply(GDBusMessage* reply) { if (!reply) throw std::runtime_error("Async reply is invalid"); } void rt::DBusAsyncReply::set_async_result(GDBusMessage* message) { promise.set_value(message); } void rt::DBusAsyncReplyVoid::get() { auto reply = rt::DBusAsyncReply::get(); throw_on_invalid_reply(reply); throw_on_error_reply(reply); } int rt::DBusAsyncReplyInt::get() { auto reply = rt::DBusAsyncReply::get(); throw_on_invalid_reply(reply); throw_on_error_reply(reply); auto body = g_dbus_message_get_body(reply); auto child = g_variant_get_child_value(body, 0); auto val = g_variant_get_int32(child); g_variant_unref(child); return val; } bool rt::DBusAsyncReplyBool::get() { auto reply = rt::DBusAsyncReply::get(); throw_on_invalid_reply(reply); throw_on_error_reply(reply); auto body = g_dbus_message_get_body(reply); auto child = g_variant_get_child_value(body, 0); auto val = g_variant_get_boolean(child); g_variant_unref(child); return val == TRUE; } std::string rt::DBusAsyncReplyString::get() { auto reply = rt::DBusAsyncReply::get(); throw_on_invalid_reply(reply); throw_on_error_reply(reply); auto body = g_dbus_message_get_body(reply); auto child = g_variant_get_child_value(body, 0); auto val = g_variant_get_string(child, nullptr); g_variant_unref(child); return std::string{val}; } rt::DBusClient::DBusClient( std::string const& bus_address, std::string const& destination, std::string const& path) : connection{bus_address.c_str()}, event_loop{destination}, destination{destination}, path{path} { } void rt::DBusClient::DBusClient::disconnect() { if (!g_dbus_connection_is_closed(connection)) g_dbus_connection_close_sync(connection, nullptr, nullptr); } std::string rt::DBusClient::DBusClient::unique_name() { auto const str = g_dbus_connection_get_unique_name(connection); return str ? str : ":invalid"; } void rt::DBusClient::emit_signal( char const* interface, char const* name, GVariant* args) { g_dbus_connection_emit_signal( connection, nullptr, path.c_str(), interface, name, args, nullptr); } void rt::DBusClient::emit_signal_full( char const* path, char const* interface, char const* name, GVariant* args) { g_dbus_connection_emit_signal( connection, nullptr, path, interface, name, args, nullptr); } void rt::DBusClient::invoke_async( DBusAsyncReply* reply, char const* interface, char const* method, GVariant* args) { static int const timeout_ms = 5000; reply->set_pending(); event_loop.enqueue( [this, reply, interface, method, args] { repowerd::DBusMessageHandle msg{ g_dbus_message_new_method_call( destination.c_str(), path.c_str(), interface, method), args}; g_dbus_connection_send_message_with_reply( connection, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, timeout_ms, nullptr, nullptr, reinterpret_cast(&DBusAsyncReply::static_set_async_result), reply); }); } repowerd-2023.07/tests/adapter-tests/dbus_client.h000066400000000000000000000056761446034100200221140ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/dbus_connection_handle.h" #include "src/adapters/dbus_event_loop.h" #include #include #include namespace repowerd { class DBusMessageHandle; namespace test { class DBusAsyncReply { public: DBusAsyncReply(DBusAsyncReply const&) = delete; DBusAsyncReply& operator=(DBusAsyncReply const&) = delete; DBusAsyncReply() = default; DBusAsyncReply(DBusAsyncReply&& other); ~DBusAsyncReply(); DBusMessageHandle get(); void set_pending(); static void static_set_async_result( GDBusConnection* connection, GAsyncResult* result, DBusAsyncReply* reply); protected: void throw_on_error_reply(GDBusMessage* reply); void throw_on_invalid_reply(GDBusMessage* reply); private: void set_async_result(GDBusMessage* message); bool pending = false; std::promise promise; }; class DBusAsyncReplyVoid : public DBusAsyncReply { public: using DBusAsyncReply::DBusAsyncReply; void get(); }; class DBusAsyncReplyInt : public DBusAsyncReply { public: using DBusAsyncReply::DBusAsyncReply; int get(); }; class DBusAsyncReplyBool : public DBusAsyncReply { public: using DBusAsyncReply::DBusAsyncReply; bool get(); }; class DBusAsyncReplyString : public DBusAsyncReply { public: using DBusAsyncReply::DBusAsyncReply; std::string get(); }; class DBusClient { public: DBusClient( std::string const& bus_address, std::string const& destination, std::string const& path); void disconnect(); std::string unique_name(); template T invoke_with_reply( char const* interface, char const* method, GVariant* args) { T t; invoke_async(&t, interface, method, args); return t; } void emit_signal(char const* interface, char const* name, GVariant* args); void emit_signal_full(char const* path, char const* interface, char const* name, GVariant* args); protected: void invoke_async( DBusAsyncReply* reply, char const* interface, char const* method, GVariant* args); DBusConnectionHandle connection; DBusEventLoop event_loop; std::string const destination; std::string const path; std::string const interface; }; } } repowerd-2023.07/tests/adapter-tests/duration_of.h000066400000000000000000000020201446034100200221060ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include namespace repowerd { namespace test { template std::chrono::milliseconds duration_of(T const& callable) { auto const start = std::chrono::steady_clock::now(); callable(); return std::chrono::duration_cast( std::chrono::steady_clock::now() - start); } } } repowerd-2023.07/tests/adapter-tests/fake_brightness_notification.cpp000066400000000000000000000026011446034100200260410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_brightness_notification.h" namespace rt = repowerd::test; rt::FakeBrightnessNotification::FakeBrightnessNotification() : brightness_handler{[](double){}} { } void rt::FakeBrightnessNotification::emit_brightness(double brightness) { brightness_handler(brightness); } repowerd::HandlerRegistration rt::FakeBrightnessNotification::register_brightness_handler( repowerd::BrightnessHandler const& handler) { mock.register_brightness_handler(handler); this->brightness_handler = handler; return repowerd::HandlerRegistration{ [this] { mock.unregister_brightness_handler(); this->brightness_handler = [](double){}; }}; } repowerd-2023.07/tests/adapter-tests/fake_brightness_notification.h000066400000000000000000000026121446034100200255100ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/brightness_notification.h" #include namespace repowerd { namespace test { class FakeBrightnessNotification : public repowerd::BrightnessNotification { public: FakeBrightnessNotification(); repowerd::HandlerRegistration register_brightness_handler( repowerd::BrightnessHandler const& handler) override; void emit_brightness(double b); struct MockMethods { MOCK_METHOD1(register_brightness_handler, void(repowerd::BrightnessHandler const&)); MOCK_METHOD0(unregister_brightness_handler, void()); }; testing::NiceMock mock; private: repowerd::BrightnessHandler brightness_handler; }; } } repowerd-2023.07/tests/adapter-tests/fake_chrono.cpp000066400000000000000000000022161446034100200224150ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_chrono.h" namespace rt = repowerd::test; rt::FakeChrono::FakeChrono() : now{0} { } void rt::FakeChrono::sleep_for(std::chrono::nanoseconds t) { std::lock_guard lock{now_mutex}; now += t; } std::chrono::steady_clock::time_point rt::FakeChrono::steady_now() { std::lock_guard lock{now_mutex}; using namespace std::chrono; return steady_clock::time_point{duration_cast(now)}; } repowerd-2023.07/tests/adapter-tests/fake_chrono.h000066400000000000000000000020571446034100200220650ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/chrono.h" #include namespace repowerd { namespace test { class FakeChrono : public Chrono { public: FakeChrono(); void sleep_for(std::chrono::nanoseconds t) override; std::chrono::steady_clock::time_point steady_now() override; private: std::mutex now_mutex; std::chrono::nanoseconds now; }; } } repowerd-2023.07/tests/adapter-tests/fake_device_config.cpp000066400000000000000000000033141446034100200237110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_device_config.h" repowerd::test::FakeDeviceConfig::FakeDeviceConfig() { set("screenBrightnessDim", std::to_string(brightness_dim_value)); set("screenBrightnessSettingMinimum", std::to_string(brightness_min_value)); set("screenBrightnessSettingMaximum", std::to_string(brightness_max_value)); set("screenBrightnessSettingDefault", std::to_string(brightness_default_value)); set("automatic_brightness_available", "true"); set("shutdownBatteryTemperature", std::to_string(shutdown_battery_temperature)); } std::string repowerd::test::FakeDeviceConfig::get( std::string const& name, std::string const& default_prop_value) const { auto const iter = properties.find(name); if (iter != properties.end()) return iter->second; else return default_prop_value; } void repowerd::test::FakeDeviceConfig::set( std::string const& name, std::string const& value) { properties[name] = value; } void repowerd::test::FakeDeviceConfig::clear() { properties.clear(); } repowerd-2023.07/tests/adapter-tests/fake_device_config.h000066400000000000000000000026511446034100200233610ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/device_config.h" #include namespace repowerd { namespace test { struct FakeDeviceConfig : repowerd::DeviceConfig { FakeDeviceConfig(); std::string get( std::string const& name, std::string const& default_prop_value) const override; void set(std::string const& name, std::string const& value); void clear(); int const brightness_dim_value = 5; int const brightness_min_value = 2; int const brightness_max_value = 100; int const brightness_default_value = 50; bool const brightness_autobrightness_supported = true; int const shutdown_battery_temperature = 990; private: std::unordered_map properties; }; } } repowerd-2023.07/tests/adapter-tests/fake_device_info.cpp000066400000000000000000000015611446034100200234010ustar00rootroot00000000000000/* * Copyright © 2022 UBports Foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #include "fake_device_info.h" namespace rt = repowerd::test; std::string rt::FakeDeviceInfo::name() { return name_; } bool rt::FakeDeviceInfo::is_desktop() { return is_desktop_; }repowerd-2023.07/tests/adapter-tests/fake_device_info.h000066400000000000000000000021521446034100200230430ustar00rootroot00000000000000/* * Copyright © 2022 UBports Foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marius Gripsgard */ #pragma once #include "src/adapters/device_info.h" namespace repowerd { namespace test { class FakeDeviceInfo : public DeviceInfo { public: FakeDeviceInfo() = default; std::string name() override; bool is_desktop() override; void set_name(std::string name) { name_ = name; } void set_is_desktop(bool val) { is_desktop_ = val; } private: std::string name_ = "fakedevice"; bool is_desktop_ = false; }; } }repowerd-2023.07/tests/adapter-tests/fake_device_quirks.cpp000066400000000000000000000037301446034100200237640ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_device_quirks.h" namespace rt = repowerd::test; rt::FakeDeviceQuirks::FakeDeviceQuirks() : synthetic_initial_event_type_{DeviceQuirks::ProximityEventType::far}, normal_before_display_on_autobrightness_{false}, ignore_session_deactivation_{false} { } std::chrono::milliseconds rt::FakeDeviceQuirks::synthetic_initial_proximity_event_delay() const { // Set a high delay to account for valgrind slowness return std::chrono::milliseconds{1000}; } repowerd::DeviceQuirks::ProximityEventType rt::FakeDeviceQuirks::synthetic_initial_proximity_event_type() const { return synthetic_initial_event_type_; } bool rt::FakeDeviceQuirks::normal_before_display_on_autobrightness() const { return normal_before_display_on_autobrightness_; } bool rt::FakeDeviceQuirks::ignore_session_deactivation() const { return ignore_session_deactivation_; } void rt::FakeDeviceQuirks::set_synthetic_initial_event_type_near() { synthetic_initial_event_type_ = repowerd::DeviceQuirks::ProximityEventType::near; } void rt::FakeDeviceQuirks::set_normal_before_display_on_autobrightness(bool value) { normal_before_display_on_autobrightness_ = value; } void rt::FakeDeviceQuirks::set_ignore_session_deactivation(bool value) { ignore_session_deactivation_ = value; } repowerd-2023.07/tests/adapter-tests/fake_device_quirks.h000066400000000000000000000027771446034100200234430ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/device_quirks.h" namespace repowerd { namespace test { struct FakeDeviceQuirks : repowerd::DeviceQuirks { FakeDeviceQuirks(); std::chrono::milliseconds synthetic_initial_proximity_event_delay() const override; DeviceQuirks::ProximityEventType synthetic_initial_proximity_event_type() const override; bool normal_before_display_on_autobrightness() const override; bool ignore_session_deactivation() const override; void set_synthetic_initial_event_type_near(); void set_normal_before_display_on_autobrightness(bool value); void set_ignore_session_deactivation(bool value); private: repowerd::DeviceQuirks::ProximityEventType synthetic_initial_event_type_; bool normal_before_display_on_autobrightness_; bool ignore_session_deactivation_; }; } } repowerd-2023.07/tests/adapter-tests/fake_double_tap_to_wake.cpp000066400000000000000000000021741446034100200247570ustar00rootroot00000000000000/* * Copyright © 2022 UBports foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexander Martinz */ #include "fake_double_tap_to_wake.h" namespace rt = repowerd::test; rt::FakeDoubleTapToWake::FakeDoubleTapToWake( std::shared_ptr const& log, std::shared_ptr const& filesystem) : repowerd::FsDoubleTapToWake(log, filesystem) { auto configvalue = "/proc/touchpanel/double_tap_enable|1|0,/sys/devices/platform/soc/a84000.i2c/i2c-2/2-0020/input/input1/wake_gesture|on|off"; parse_config(configvalue); } repowerd-2023.07/tests/adapter-tests/fake_double_tap_to_wake.h000066400000000000000000000023201446034100200244150ustar00rootroot00000000000000/* * Copyright © 2022 UBports foundation. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexander Martinz */ #pragma once #include "src/adapters/fs_double_tap_to_wake.h" namespace repowerd { namespace test { class FakeDoubleTapToWake : public repowerd::FsDoubleTapToWake { public: FakeDoubleTapToWake( std::shared_ptr const& log, std::shared_ptr const& filesystem); bool is_enabled() { return false; }; bool is_supported() { return false; }; void enable() { /* do nothing */ }; void disable() { /* do nothing */ }; protected: void set_enabled(bool) { /* do nothing */ }; }; } }repowerd-2023.07/tests/adapter-tests/fake_filesystem.cpp000066400000000000000000000110141446034100200233050ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_filesystem.h" #include "src/adapters/fd.h" #include #include #include namespace { std::vector split_dirs(std::string const& path) { std::vector dirs; size_t sep = 0; while ((sep = path.find_first_of('/', sep)) != std::string::npos) { if (sep == 0) dirs.push_back("/"); else dirs.push_back(path.substr(0, sep)); ++sep; } return dirs; } class LiveStreamBuf : public std::streambuf { public: LiveStreamBuf(std::string& str) : str{str} { } private: int_type overflow(int_type c) override { if (c != EOF) str.push_back(c); return c; } std::string& str; }; class LiveOStream : public std::ostream { public: LiveOStream(std::unique_ptr streambuf) : std::ostream{streambuf.get()}, streambuf{std::move(streambuf)} { } private: std::unique_ptr const streambuf; }; } repowerd::test::FakeFilesystem::~FakeFilesystem() { EXPECT_TRUE(paths.empty()) << "Open files at exit"; } bool repowerd::test::FakeFilesystem::is_regular_file( std::string const& path) const { return files.find(path) != files.end(); } std::unique_ptr repowerd::test::FakeFilesystem::istream( std::string const& path) const { if (files.find(path) == files.end()) { return std::make_unique(""); } else { return std::make_unique(files.at(path)->back()); } } std::unique_ptr repowerd::test::FakeFilesystem::ostream( std::string const& path) const { if (files.find(path) == files.end()) { return std::make_unique(""); } else { files[path]->push_back(""); return std::make_unique( std::make_unique(files[path]->back())); } } std::vector repowerd::test::FakeFilesystem::subdirs( std::string const& path) const { std::vector return_dirs; for (auto const& dir : directories) { if (dir.size() > path.size() && dir.find(path) == 0 && dir[path.size()] == '/' && dir.find_last_of('/') == path.size()) { return_dirs.push_back(dir); } } return return_dirs; } repowerd::Fd repowerd::test::FakeFilesystem::open( char const* path, int) const { int fd = 100; for (; fd < 200; ++fd) if (paths.find(fd) == paths.end()) break; paths[fd] = path; return {fd, [this](int fd) { paths.erase(fd); return 0; }}; } int repowerd::test::FakeFilesystem::ioctl( int fd, unsigned long request, void* args) const { if (paths.find(fd) == paths.end()) return -1; auto const& path = paths[fd]; if (ioctl_handlers.find(path) == ioctl_handlers.end()) return -1; else return ioctl_handlers.at(path)(path.c_str(), request, args); } void repowerd::test::FakeFilesystem::add_file_with_contents( std::string const& path, std::string const& contents) { files[path] = std::make_shared>(); files[path]->push_back(contents); auto const dirs = split_dirs(path); for (auto const& dir : dirs) add_dir(dir); } std::shared_ptr> repowerd::test::FakeFilesystem::add_file_with_live_contents( std::string const& path) { files[path] = std::make_shared>(); return files[path]; } void repowerd::test::FakeFilesystem::add_file_ioctl( std::string const& path, FakeFilesystemIoctlHandler const& handler) { add_file_with_contents(path, ""); ioctl_handlers[path] = handler; } void repowerd::test::FakeFilesystem::add_dir( std::string const& path) { directories.insert(path); } repowerd-2023.07/tests/adapter-tests/fake_filesystem.h000066400000000000000000000041211446034100200227530ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/filesystem.h" #include #include #include #include namespace repowerd { namespace test { using FakeFilesystemIoctlHandler = std::function; class FakeFilesystem : public Filesystem { public: ~FakeFilesystem(); bool is_regular_file(std::string const& path) const override; std::unique_ptr istream(std::string const& path) const override; std::unique_ptr ostream(std::string const& path) const override; std::vector subdirs(std::string const& path) const override; Fd open(char const* pathname, int flags) const override; int ioctl(int fd, unsigned long request, void* args) const override; void add_file_with_contents(std::string const& path, std::string const& contents); std::shared_ptr> add_file_with_live_contents( std::string const& path); void add_file_ioctl(std::string const& path, FakeFilesystemIoctlHandler const& handler); private: void add_dir(std::string const& path); mutable std::unordered_map>> files; std::unordered_set directories; mutable std::unordered_map paths; std::unordered_map ioctl_handlers; }; } } repowerd-2023.07/tests/adapter-tests/fake_libhardware.cpp000066400000000000000000000107551446034100200234200ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_libhardware.h" #include namespace rt = repowerd::test; namespace { struct HwModule : hw_module_t { HwModule(std::function const& open_func) : open_func{open_func} { fake_methods.open = static_open; methods = &fake_methods; } static int static_open(hw_module_t const* module, const char* id, hw_device_t** device) { auto fake_module = reinterpret_cast(module); return fake_module->open_func(id, device); } std::function const open_func; hw_module_methods_t fake_methods; }; struct LightHwDevice : light_device_t { LightHwDevice( std::function const& close_func, std::function const& set_light_func) : close_func{close_func}, set_light_func{set_light_func} { common.close = static_close; set_light = static_set_light; } static int static_close(hw_device_t* dev) { auto light_device = reinterpret_cast(dev); return light_device->close_func(); } static int static_set_light(light_device_t* dev, light_state_t const* state) { auto light_device = reinterpret_cast(dev); return light_device->set_light_func(state); } std::function const close_func; std::function const set_light_func; }; struct LightsHwModule : HwModule { LightsHwModule(std::function const& set_light_func) : HwModule( [this] (const char* id, hw_device_t** device) -> int { return lights_open(id, device); }), fake_light_device{[this]{ return lights_close(); }, set_light_func}, is_open{false} { } int lights_open(char const* id, hw_device_t** device) { if (std::string{id} == LIGHT_ID_BACKLIGHT) { *device = &fake_light_device.common; is_open = true; return 0; } else { *device = nullptr; return -1; } } int lights_close() { is_open = false; return 0; } LightHwDevice fake_light_device; bool is_open; }; } int hw_get_module(char const* id, hw_module_t const** module) { return rt::FakeLibhardware::static_hw_get_module(id, module); } rt::FakeLibhardware* rt::FakeLibhardware::FakeLibhardware::fake_libhardware_instance = nullptr; rt::FakeLibhardware::FakeLibhardware() : lights_module{ std::make_unique( [this] (light_state_t const* state) -> int { return set_light(state); })} { fake_libhardware_instance = this; } rt::FakeLibhardware::~FakeLibhardware() { fake_libhardware_instance = nullptr; } bool rt::FakeLibhardware::is_lights_module_open() { return reinterpret_cast(lights_module.get())->is_open; } std::vector rt::FakeLibhardware::backlight_state_history() { return backlight_state_history_; } int rt::FakeLibhardware::static_hw_get_module(char const* id, hw_module_t const** module) { if (!fake_libhardware_instance) throw std::runtime_error("Fake libhardware instance not initialized"); return fake_libhardware_instance->hw_get_module(id, module); } int rt::FakeLibhardware::hw_get_module(char const* id, hw_module_t const** module) { if (std::string{id} == LIGHTS_HARDWARE_MODULE_ID) { *module = lights_module.get(); return 0; } else { *module = nullptr; return -1; } } int rt::FakeLibhardware::set_light(light_state_t const* state) { backlight_state_history_.push_back(*state); return 0; } repowerd-2023.07/tests/adapter-tests/fake_libhardware.h000066400000000000000000000025441446034100200230620ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include #include namespace repowerd { namespace test { class FakeLibhardware { public: FakeLibhardware(); ~FakeLibhardware(); bool is_lights_module_open(); std::vector backlight_state_history(); static int static_hw_get_module(char const* id, hw_module_t const** module); private: static FakeLibhardware* fake_libhardware_instance; int hw_get_module(char const* id, hw_module_t const** module); int set_light(light_state_t const* state); std::unique_ptr lights_module; std::vector backlight_state_history_; }; } } repowerd-2023.07/tests/adapter-tests/fake_logind.cpp000066400000000000000000000365041446034100200224100ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_logind.h" #include #include #include namespace rt = repowerd::test; using namespace std::literals::string_literals; namespace { char const* const logind_introspection = R"( )"; char const* const logind_seat_introspection = R"( )"; char const* const logind_session_introspection = R"( )"; char const* const seat_path = "/org/freedesktop/login1/seat/seat0"; std::string session_path_for_id(std::string const& session_id) { return "/org/freedesktop/login1/session/" + session_id; } std::string session_id_for_path(std::string const& session_path) { return session_path.substr(session_path.rfind("/") + 1); } } rt::FakeLogind::FakeLogind( std::string const& dbus_address) : rt::DBusClient{dbus_address, "org.freedesktop.login1", "/org/freedesktop/login1"} { connection.request_name("org.freedesktop.login1"); logind_handler_registration = event_loop.register_object_handler( connection, "/org/freedesktop/login1", logind_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); logind_seat_handler_registration = event_loop.register_object_handler( connection, seat_path, logind_seat_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); } void rt::FakeLogind::add_session( std::string const& session_id, std::string const& session_type, pid_t pid, uid_t uid) { { std::lock_guard lock{sessions_mutex}; sessions[session_id] = {session_type, pid, uid}; } auto const session_path = session_path_for_id(session_id); session_handler_registrations[session_id] = event_loop.register_object_handler( connection, session_path.c_str(), logind_session_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); auto const params = g_variant_new_parsed("(@s %s, @o %o)", session_id.c_str(),session_path.c_str()); emit_signal_full( "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "SessionAdded", params); } void rt::FakeLogind::remove_session(std::string const& session_id) { { std::lock_guard lock{sessions_mutex}; sessions.erase(session_id); } session_handler_registrations.erase(session_id); auto const session_path = session_path_for_id(session_id); auto const params = g_variant_new_parsed("(@s %s, @o %o)", session_id.c_str(), session_path.c_str()); emit_signal_full( "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "SessionRemoved", params); } void rt::FakeLogind::activate_session(std::string const& session_id) { { std::lock_guard lock{sessions_mutex}; if (sessions.find(session_id) == sessions.end()) throw std::runtime_error("Cannot activate non-existent session " + session_id); active_session_id = session_id; } auto const session_path = session_path_for_id(session_id); auto const changed_properties_str = "'ActiveSession': <(@s '"s + session_id + "', @o '" + session_path + "')>"; auto const params_str = "(@s 'org.freedesktop.login1.Seat',"s + " @a{sv} {" + changed_properties_str + "}," + " @as [])"; auto const params = g_variant_new_parsed(params_str.c_str()); emit_signal_full( seat_path, "org.freedesktop.DBus.Properties", "PropertiesChanged", params); } void rt::FakeLogind::deactivate_session() { auto const changed_properties_str = "'ActiveSession': <(@s '', @o '/')>"; auto const params_str = "(@s 'org.freedesktop.login1.Seat',"s + " @a{sv} {" + changed_properties_str + "}," + " @as [])"; auto const params = g_variant_new_parsed(params_str.c_str()); emit_signal_full( seat_path, "org.freedesktop.DBus.Properties", "PropertiesChanged", params); } std::unordered_set rt::FakeLogind::active_inhibitions() { std::lock_guard lock{sessions_mutex}; std::unordered_set ret; for (auto iter = inhibitions.begin(); iter != inhibitions.end(); ) { char c = 0; if (read(iter->second, &c, 1) == 0) { iter = inhibitions.erase(iter); } else { ret.insert(iter->first); ++iter; } } return ret; } std::string rt::FakeLogind::power_requests() { std::lock_guard lock{sessions_mutex}; return power_requests_; } void rt::FakeLogind::emit_prepare_for_sleep(bool start) { gboolean const value{start ? TRUE : FALSE}; auto const params = g_variant_new_parsed("(%b,)", value); emit_signal_full( "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForSleep", params); } void rt::FakeLogind::set_block_inhibited(std::string const& blocks) { block_inhibited = blocks; auto const changed_properties_str = "'BlockInhibited': <@s '"s + blocks + "'>"; auto const params_str = "(@s 'org.freedesktop.login1.Manager',"s + " @a{sv} {" + changed_properties_str + "}," + " @as [])"; auto const params = g_variant_new_parsed(params_str.c_str()); emit_signal_full( "/org/freedesktop/login1", "org.freedesktop.DBus.Properties", "PropertiesChanged", params); } void rt::FakeLogind::dbus_method_call( GDBusConnection* /*connection*/, gchar const* /*sender_cstr*/, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation) { std::string const object_path{object_path_cstr ? object_path_cstr : ""}; std::string const method_name{method_name_cstr ? method_name_cstr : ""}; std::string const interface_name{interface_name_cstr ? interface_name_cstr : ""}; if (interface_name == "org.freedesktop.DBus.Properties" && method_name == "Get" && object_path == seat_path) { std::string local_active_session_id; { std::lock_guard lock{sessions_mutex}; local_active_session_id = active_session_id; } auto const local_active_session_path = session_path_for_id(local_active_session_id); auto const properties = g_variant_new_parsed("(<(@s %s, @o %o)>,)", local_active_session_id.c_str(), local_active_session_path.c_str()); g_dbus_method_invocation_return_value(invocation, properties); } else if (interface_name == "org.freedesktop.DBus.Properties" && method_name == "Get" && sessions.find(session_id_for_path(object_path)) != sessions.end()) { char const* property_name_cstr{""}; g_variant_get(parameters, "(&s&s)", nullptr, &property_name_cstr); std::string const property_name{property_name_cstr ? property_name_cstr : ""}; GVariant* property = nullptr; { std::lock_guard lock{sessions_mutex}; auto const iter = sessions.find(session_id_for_path(object_path)); if (iter != sessions.end()) { if (property_name == "Type") { property = g_variant_new_parsed( "(<%s>,)", iter->second.type.c_str()); } else if (property_name == "User") { auto const user_path = "/org/freedesktop/login1/user/_" + std::to_string(iter->second.uid); property = g_variant_new_parsed( "(<(@u %u, @o %o)>,)", iter->second.uid, user_path.c_str()); } } } g_dbus_method_invocation_return_value(invocation, property); } else if (interface_name == "org.freedesktop.DBus.Properties" && method_name == "Get" && object_path == "/org/freedesktop/login1") { char const* property_name_cstr{""}; g_variant_get(parameters, "(&s&s)", nullptr, &property_name_cstr); std::string const property_name{property_name_cstr ? property_name_cstr : ""}; GVariant* property = nullptr; if (property_name == "BlockInhibited") { property = g_variant_new_parsed( "(<%s>,)", block_inhibited.c_str()); } g_dbus_method_invocation_return_value(invocation, property); } else if (interface_name == "org.freedesktop.login1.Manager" && method_name == "GetSessionByPID") { guint gpid = -1; g_variant_get(parameters, "(u)", &gpid); pid_t const pid = gpid; std::string session_path; { std::lock_guard lock{sessions_mutex}; auto const iter = std::find_if( sessions.begin(), sessions.end(), [pid] (auto const& kv) { return kv.second.pid == pid; }); if (iter != sessions.end()) session_path = session_path_for_id(iter->first); } if (session_path.empty()) { g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, ""); } else { auto const session_variant = g_variant_new_parsed("(%o,)", session_path.c_str()); g_dbus_method_invocation_return_value(invocation, session_variant); } } else if (interface_name == "org.freedesktop.login1.Manager" && method_name == "Inhibit") { char const* what_cstr = nullptr; char const* who_cstr = nullptr; char const* why_cstr = nullptr; char const* mode_cstr = nullptr; g_variant_get(parameters, "(&s&s&s&s)", &what_cstr, &who_cstr, &why_cstr, &mode_cstr); int pipefd[2]; if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) pipefd[0] = pipefd[1] = -1; auto inhibition_id = std::string{what_cstr} + "," + who_cstr + "," + why_cstr + "," + mode_cstr; { std::lock_guard lock{sessions_mutex}; inhibitions.emplace(inhibition_id, Fd{pipefd[0]}); } auto const reply = g_variant_new_parsed("(@h 0,)"); auto const fd_list = g_unix_fd_list_new_from_array(pipefd + 1, 1); g_dbus_method_invocation_return_value_with_unix_fd_list( invocation, reply, fd_list); g_object_unref(fd_list); } else if (interface_name == "org.freedesktop.login1.Manager" && method_name == "PowerOff") { gboolean interactive = TRUE; g_variant_get(parameters, "(b)", &interactive); { std::lock_guard lock{sessions_mutex}; power_requests_.append(interactive ? "[power-off:t]" : "[power-off:f]"); } g_dbus_method_invocation_return_value(invocation, nullptr); } else if (interface_name == "org.freedesktop.login1.Manager" && method_name == "Suspend") { gboolean interactive = TRUE; g_variant_get(parameters, "(b)", &interactive); { std::lock_guard lock{sessions_mutex}; power_requests_.append(interactive ? "[suspend:t]" : "[suspend:f]"); } g_dbus_method_invocation_return_value(invocation, nullptr); } else { g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); } } repowerd-2023.07/tests/adapter-tests/fake_logind.h000066400000000000000000000045221446034100200220500ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "dbus_client.h" #include "src/adapters/fd.h" #include #include #include #include #include namespace repowerd { namespace test { class FakeLogind : private DBusClient { public: FakeLogind(std::string const& dbus_address); void add_session( std::string const& session_path, std::string const& session_type, pid_t pid, uid_t uid); void remove_session(std::string const& session_path); void activate_session(std::string const& session_path); void deactivate_session(); std::unordered_set active_inhibitions(); std::string power_requests(); void emit_prepare_for_sleep(bool start); void set_block_inhibited(std::string const& blocks); private: void dbus_method_call( GDBusConnection* connection, gchar const* sender_cstr, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation); repowerd::HandlerRegistration logind_handler_registration; repowerd::HandlerRegistration logind_seat_handler_registration; struct SessionInfo { std::string type; pid_t pid; uid_t uid; }; std::mutex sessions_mutex; std::unordered_map sessions; std::unordered_map session_handler_registrations; std::string active_session_id; std::unordered_map inhibitions; std::string power_requests_; std::string block_inhibited; }; } } repowerd-2023.07/tests/adapter-tests/fake_ofono.cpp000066400000000000000000000170001446034100200222420ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_ofono.h" namespace rt = repowerd::test; namespace { char const* const ofono_manager_introspection = R"( )"; char const* const ofono_modem_introspection = R"( )"; std::string ofono_call_state_to_string(repowerd::OfonoCallState state) { switch (state) { case repowerd::OfonoCallState::active: return "active"; case repowerd::OfonoCallState::alerting: return "alerting"; case repowerd::OfonoCallState::dialing: return "dialing"; case repowerd::OfonoCallState::disconnected: return "disconnected"; case repowerd::OfonoCallState::held: return "held"; case repowerd::OfonoCallState::incoming: return "incoming"; case repowerd::OfonoCallState::waiting: return "waiting"; case repowerd::OfonoCallState::invalid: default: return ""; }; return ""; } } rt::FakeOfono::FakeOfono( std::string const& dbus_address) : rt::DBusClient{dbus_address, "org.ofono", "/phonesim"} { connection.request_name("org.ofono"); manager_handler_registration = event_loop.register_object_handler( connection, "/", ofono_manager_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); } void rt::FakeOfono::add_call( std::string const& call_path, repowerd::OfonoCallState call_state) { auto const params = g_variant_new_parsed( "(@o %o, @a{sv} {'Name': <'bla'>, 'State': <%s>, 'Emergency': })", call_path.c_str(), ofono_call_state_to_string(call_state).c_str()); emit_signal("org.ofono.VoiceCallManager", "CallAdded", params); } void rt::FakeOfono::remove_call(std::string const& call_path) { auto const params = g_variant_new_parsed("(@o %o,)", call_path.c_str()); emit_signal("org.ofono.VoiceCallManager", "CallRemoved", params); } void rt::FakeOfono::change_call_state( std::string const& call_path, repowerd::OfonoCallState call_state) { auto const params = g_variant_new_parsed( "('State',<%s>)", ofono_call_state_to_string(call_state).c_str()); emit_signal_full(call_path.c_str(), "org.ofono.VoiceCall", "PropertyChanged", params); } void rt::FakeOfono::add_modem(std::string const& modem_path) { { std::lock_guard lock{modems_mutex}; modems[modem_path] = ModemPowerState::normal; modems_cv.notify_one(); } modem_handler_registrations[modem_path] = event_loop.register_object_handler( connection, modem_path.c_str(), ofono_modem_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); auto const params = g_variant_new_parsed("(@o %o, @a{sv} {})", modem_path.c_str()); emit_signal_full("/", "org.ofono.Manager", "ModemAdded", params); } void rt::FakeOfono::remove_modem(std::string const& modem_path) { { std::lock_guard lock{modems_mutex}; modems.erase(modem_path); modems_cv.notify_one(); } modem_handler_registrations.erase(modem_path); auto const params = g_variant_new_parsed("(@o %o,)", modem_path.c_str()); emit_signal_full("/", "org.ofono.Manager", "ModemRemoved", params); } bool rt::FakeOfono::wait_for_modems_condition( std::function const& condition, std::chrono::milliseconds timeout) { std::unique_lock lock{modems_mutex}; return modems_cv.wait_for(lock, timeout, [this,&condition]{ return condition(modems);}); } void rt::FakeOfono::dbus_method_call( GDBusConnection* /*connection*/, gchar const* /*sender_cstr*/, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation) { std::string const object_path{object_path_cstr ? object_path_cstr : ""}; std::string const method_name{method_name_cstr ? method_name_cstr : ""}; std::string const interface_name{interface_name_cstr ? interface_name_cstr : ""}; if (method_name == "GetModems") { std::string modems_str = "(["; int count = 0; for (auto const& modem : modems) { if (count++ > 0) modems_str += ", "; modems_str += "(@o '" + modem.first + "', @a{sv} {})"; } modems_str += "],)"; auto const modems = g_variant_new_parsed(modems_str.c_str()); g_dbus_method_invocation_return_value(invocation, modems); } else if (interface_name == "org.ofono.RadioSettings" && method_name == "SetProperty") { char const* property{""}; GVariant* value{nullptr}; g_variant_get(parameters, "(&sv)", &property, &value); if (std::string{property} == "FastDormancy") { std::lock_guard lock{modems_mutex}; auto const fast_dormancy = g_variant_get_boolean(value); if (fast_dormancy) modems[object_path] = ModemPowerState::low; else modems[object_path] = ModemPowerState::normal; modems_cv.notify_one(); } g_variant_unref(value); g_dbus_method_invocation_return_value(invocation, nullptr); } } repowerd-2023.07/tests/adapter-tests/fake_ofono.h000066400000000000000000000042131446034100200217110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/ofono_voice_call_service.h" #include "dbus_client.h" #include #include #include #include #include namespace repowerd { namespace test { class FakeOfono : private DBusClient { public: enum class ModemPowerState{normal, low}; using Modems = std::unordered_map; FakeOfono(std::string const& dbus_address); void add_call(std::string const& call_path, repowerd::OfonoCallState call_state); void remove_call(std::string const& call_path); void change_call_state(std::string const& call_path, repowerd::OfonoCallState call_state); void add_modem(std::string const& modem_path); void remove_modem(std::string const& modem_path); bool wait_for_modems_condition( std::function const& condition, std::chrono::milliseconds timeout); private: void dbus_method_call( GDBusConnection* connection, gchar const* sender_cstr, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation); repowerd::HandlerRegistration manager_handler_registration; std::mutex modems_mutex; std::condition_variable modems_cv; Modems modems; std::unordered_map modem_handler_registrations; }; } } repowerd-2023.07/tests/adapter-tests/fake_upower.cpp000066400000000000000000000256451446034100200224610ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_upower.h" namespace rt = repowerd::test; using namespace std::literals::string_literals; namespace { char const* const upower_introspection = R"( )"; char const* const upower_device_introspection = R"( )"; char const* const display_device_path = "/org/freedesktop/UPower/devices/DisplayDevice"; } rt::FakeUPower::DeviceInfo rt::FakeUPower::DeviceInfo::for_battery(DeviceState state) { DeviceInfo info; info.type = DeviceType::battery; info.online = false; info.percentage = 100.0; info.temperature = 18.0; info.is_present = true; info.state = state; return info; } rt::FakeUPower::DeviceInfo rt::FakeUPower::DeviceInfo::for_plugged_line_power() { DeviceInfo info; info.type = DeviceType::line_power; info.online = true; info.percentage = 0.0; info.temperature = 0.0; info.is_present = true; info.state = DeviceState::unknown; return info; } rt::FakeUPower::DeviceInfo rt::FakeUPower::DeviceInfo::for_unplugged_line_power() { DeviceInfo info; info.type = DeviceType::line_power; info.online = false; info.percentage = 0.0; info.temperature = 0.0; info.is_present = true; info.state = DeviceState::unknown; return info; } rt::FakeUPower::FakeUPower( std::string const& dbus_address) : rt::DBusClient{dbus_address, "org.freedesktop.UPower", "/org/freedesktop/UPower"}, num_enumerate_device_calls_{0} { connection.request_name("org.freedesktop.UPower"); upower_handler_registration = event_loop.register_object_handler( connection, "/org/freedesktop/UPower", upower_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); } void rt::FakeUPower::add_device(std::string const& device_path, DeviceInfo const& info) { { std::lock_guard lock{devices_mutex}; devices[device_path] = info; } device_handler_registrations[device_path] = event_loop.register_object_handler( connection, device_path.c_str(), upower_device_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); auto const params = g_variant_new_parsed("(@o %o,)", device_path.c_str()); emit_signal_full("/org/freedesktop/UPower", "org.freedesktop.UPower", "DeviceAdded", params); } void rt::FakeUPower::change_device(std::string const& device_path, DeviceInfo const& info) { DeviceInfo old_info; { std::lock_guard lock{devices_mutex}; old_info = devices[device_path]; devices[device_path] = info; } std::string changed_properties_str; if (old_info.type != info.type) { if (!changed_properties_str.empty()) changed_properties_str += ", "; changed_properties_str += "'Type': <@u " + std::to_string(static_cast(info.type)) + ">"; } if (old_info.online != info.online) { if (!changed_properties_str.empty()) changed_properties_str += ", "; changed_properties_str += "'Online': <"s + (info.online ? "true" : "false") + ">"; } if (old_info.percentage != info.percentage) { if (!changed_properties_str.empty()) changed_properties_str += ", "; changed_properties_str += "'Percentage': <" + std::to_string(info.percentage) + ">"; } if (old_info.temperature != info.temperature) { if (!changed_properties_str.empty()) changed_properties_str += ", "; changed_properties_str += "'Temperature': <" + std::to_string(info.temperature) + ">"; } if (old_info.is_present != info.is_present) { if (!changed_properties_str.empty()) changed_properties_str += ", "; changed_properties_str += "'IsPresent': <"s + (info.is_present ? "true" : "false") + ">"; } if (old_info.state != info.state) { if (!changed_properties_str.empty()) changed_properties_str += ", "; changed_properties_str += "'State': <@u " + std::to_string(static_cast(info.state)) + ">"; } auto const params_str = "(@s 'org.freedesktop.UPower.Device',"s + " @a{sv} {" + changed_properties_str + "}," + " @as [])"; auto const params = g_variant_new_parsed(params_str.c_str()); emit_signal_full(device_path.c_str(), "org.freedesktop.DBus.Properties", "PropertiesChanged", params); } void rt::FakeUPower::remove_device(std::string const& device_path) { { std::lock_guard lock{devices_mutex}; devices.erase(device_path); } device_handler_registrations.erase(device_path); auto const params = g_variant_new_parsed("(@o %o,)", device_path.c_str()); emit_signal_full("/org/freedesktop/UPower", "org.freedesktop.UPower", "DeviceRemoved", params); } void rt::FakeUPower::close_lid() { auto const params_str = "(@s 'org.freedesktop.UPower',"s + " @a{sv} {'LidIsClosed': <@b true>}," + " @as [])"; auto const params = g_variant_new_parsed(params_str.c_str()); emit_signal_full( "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "PropertiesChanged", params); } void rt::FakeUPower::open_lid() { auto const params_str = "(@s 'org.freedesktop.UPower',"s + " @a{sv} {'LidIsClosed': <@b false>}," + " @as [])"; auto const params = g_variant_new_parsed(params_str.c_str()); emit_signal_full( "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "PropertiesChanged", params); } int rt::FakeUPower::num_enumerate_devices_calls() { return num_enumerate_device_calls_; } void rt::FakeUPower::dbus_method_call( GDBusConnection* /*connection*/, gchar const* /*sender_cstr*/, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* method_name_cstr, GVariant* /*parameters*/, GDBusMethodInvocation* invocation) { std::string const object_path{object_path_cstr ? object_path_cstr : ""}; std::string const method_name{method_name_cstr ? method_name_cstr : ""}; std::string const interface_name{interface_name_cstr ? interface_name_cstr : ""}; if (method_name == "EnumerateDevices") { ++num_enumerate_device_calls_; std::string devices_str = "(["; int count = 0; for (auto const& device : devices) { // DisplayDevice is not included in the enumerated devices if (device.first == display_device_path) continue; if (count++ > 0) devices_str += ", "; devices_str += "@o '" + device.first + "'"; } devices_str += "],)"; auto const devices = g_variant_new_parsed(devices_str.c_str()); g_dbus_method_invocation_return_value(invocation, devices); } else if (interface_name == "org.freedesktop.DBus.Properties" && method_name == "GetAll") { DeviceInfo info; { std::lock_guard lock{devices_mutex}; info = devices[object_path]; } auto const properties = g_variant_new_parsed( "(@a{sv} {'Type': <%u>, 'Online': <%b>, 'Percentage': <%d>, " "'Temperature': <%d>, 'IsPresent': <%b>, 'State': <%u>},)", info.type, info.online, info.percentage, info.temperature, info.is_present, info.state); g_dbus_method_invocation_return_value(invocation, properties); } else if (interface_name == "org.freedesktop.DBus.Properties" && method_name == "Get" && object_path == "/org/freedesktop/UPower") { auto const properties = g_variant_new_parsed("(<%b>,)", is_using_battery_power()); g_dbus_method_invocation_return_value(invocation, properties); } else { g_dbus_method_invocation_return_error_literal( invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); } } bool rt::FakeUPower::is_using_battery_power() { bool on_battery = false; for (auto const& device : devices) { auto const& info = device.second; if (info.type == DeviceType::battery && info.state == DeviceState::discharging && info.is_present) { on_battery = true; } } for (auto const& device : devices) { auto const& info = device.second; if (info.type == DeviceType::line_power && info.online) { on_battery = false; } } return on_battery; } repowerd-2023.07/tests/adapter-tests/fake_upower.h000066400000000000000000000050311446034100200221110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "dbus_client.h" #include #include #include #include #include #include namespace repowerd { namespace test { class FakeUPower : private DBusClient { public: enum class DeviceState { unknown = 0, charging, discharging, empty, fully_charged, pending_charge, pending_discharge }; enum class DeviceType { unknown = 0, line_power, battery }; struct DeviceInfo { static DeviceInfo for_battery(DeviceState state); static DeviceInfo for_plugged_line_power(); static DeviceInfo for_unplugged_line_power(); DeviceType type; bool online; double percentage; double temperature; bool is_present; DeviceState state; }; FakeUPower(std::string const& dbus_address); void add_device(std::string const& device_path, DeviceInfo const& info); void remove_device(std::string const& device_path); void change_device(std::string const& device_path, DeviceInfo const& info); void close_lid(); void open_lid(); int num_enumerate_devices_calls(); private: void dbus_method_call( GDBusConnection* connection, gchar const* sender_cstr, gchar const* object_path_cstr, gchar const* interface_name_cstr, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation); bool is_using_battery_power(); repowerd::HandlerRegistration upower_handler_registration; std::atomic num_enumerate_device_calls_; std::mutex devices_mutex; std::unordered_map devices; std::unordered_map device_handler_registrations; }; } } repowerd-2023.07/tests/adapter-tests/fake_wakeup_service.cpp000066400000000000000000000037141446034100200241450ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_wakeup_service.h" namespace rt = repowerd::test; rt::FakeWakeupService::FakeWakeupService() : wakeup_handler{[](std::string const&){}} { } std::string rt::FakeWakeupService::schedule_wakeup_at( std::chrono::system_clock::time_point tp) { wakeups.push_back(tp); return std::to_string(wakeups.size() - 1); } void rt::FakeWakeupService::cancel_wakeup(std::string const& cookie) { int const cookie_int = std::stoi(cookie); wakeups.at(cookie_int) = {}; } std::chrono::system_clock::time_point rt::FakeWakeupService::emit_next_wakeup() { std::chrono::system_clock::time_point next{}; for (auto i = 0u; i < wakeups.size(); ++i) { if (wakeups[i] != std::chrono::system_clock::time_point{}) { next = wakeups[i]; wakeups[i] = {}; wakeup_handler(std::to_string(i)); } } return next; } repowerd::HandlerRegistration rt::FakeWakeupService::register_wakeup_handler( repowerd::WakeupHandler const& handler) { mock.register_wakeup_handler(handler); this->wakeup_handler = handler; return repowerd::HandlerRegistration{ [this] { mock.unregister_wakeup_handler(); this->wakeup_handler = [](std::string const&){}; }}; } repowerd-2023.07/tests/adapter-tests/fake_wakeup_service.h000066400000000000000000000031121446034100200236020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/adapters/wakeup_service.h" #include #include namespace repowerd { namespace test { class FakeWakeupService : public repowerd::WakeupService { public: FakeWakeupService(); std::string schedule_wakeup_at(std::chrono::system_clock::time_point tp) override; void cancel_wakeup(std::string const& cookie) override; repowerd::HandlerRegistration register_wakeup_handler( repowerd::WakeupHandler const& handler) override; std::chrono::system_clock::time_point emit_next_wakeup(); struct MockMethods { MOCK_METHOD1(register_wakeup_handler, void(repowerd::WakeupHandler const&)); MOCK_METHOD0(unregister_wakeup_handler, void()); }; testing::NiceMock mock; private: repowerd::WakeupHandler wakeup_handler; std::vector wakeups; }; } } repowerd-2023.07/tests/adapter-tests/repowerd_settings_dbus_client.cpp000066400000000000000000000044431446034100200262650ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "repowerd_settings_dbus_client.h" #include namespace rt = repowerd::test; namespace { char const* const repowerd_interface = "com.lomiri.Repowerd.Settings"; } rt::RepowerdSettingsDBusClient::RepowerdSettingsDBusClient(std::string const& address) : rt::DBusClient{ address, "com.lomiri.Repowerd.Settings", "/com/lomiri/Repowerd/Settings"} { } rt::DBusAsyncReplyString rt::RepowerdSettingsDBusClient::request_introspection() { return invoke_with_reply( "org.freedesktop.DBus.Introspectable", "Introspect", nullptr); } rt::DBusAsyncReplyVoid rt::RepowerdSettingsDBusClient::request_set_inactivity_behavior( std::string const& power_action, std::string const& power_supply, int32_t timeout_sec) { return invoke_with_reply( repowerd_interface, "SetInactivityBehavior", g_variant_new("(ssi)", power_action.c_str(), power_supply.c_str(), timeout_sec)); } rt::DBusAsyncReplyVoid rt::RepowerdSettingsDBusClient::request_set_lid_behavior( std::string const& power_action, std::string const& power_supply) { return invoke_with_reply( repowerd_interface, "SetLidBehavior", g_variant_new("(ss)", power_action.c_str(), power_supply.c_str())); } rt::DBusAsyncReplyVoid rt::RepowerdSettingsDBusClient::request_set_critical_power_behavior( std::string const& power_action) { return invoke_with_reply( repowerd_interface, "SetCriticalPowerBehavior", g_variant_new("(s)", power_action.c_str())); } repowerd-2023.07/tests/adapter-tests/repowerd_settings_dbus_client.h000066400000000000000000000025461446034100200257340ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "dbus_client.h" #include namespace repowerd { namespace test { class RepowerdSettingsDBusClient : public DBusClient { public: RepowerdSettingsDBusClient(std::string const& address); DBusAsyncReplyString request_introspection(); DBusAsyncReplyVoid request_set_inactivity_behavior( std::string const& power_action, std::string const& power_supply, int32_t timeout); DBusAsyncReplyVoid request_set_lid_behavior( std::string const& power_action, std::string const& power_supply); DBusAsyncReplyVoid request_set_critical_power_behavior( std::string const& power_action); }; } } repowerd-2023.07/tests/adapter-tests/run_command.cpp000066400000000000000000000022331446034100200224400ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "run_command.h" #include #include std::string repowerd::test::run_command(std::string const& cmd) { auto fp = ::popen(cmd.c_str(), "r"); if (!fp) throw std::runtime_error("Failed to execute command: " + cmd); std::string output; char buffer[64]; while (!std::feof(fp)) { auto nread = std::fread(buffer, 1, 64, fp); output.append(buffer, nread); } ::pclose(fp); return output; } repowerd-2023.07/tests/adapter-tests/run_command.h000066400000000000000000000014751446034100200221140ustar00rootroot00000000000000/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { namespace test { std::string run_command(std::string const& cmd); } } repowerd-2023.07/tests/adapter-tests/temporary_environment_value.cpp000066400000000000000000000023611446034100200260020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "temporary_environment_value.h" repowerd::test::TemporaryEnvironmentValue::TemporaryEnvironmentValue( char const* name, char const* value) : name{name}, has_old_value{getenv(name) != nullptr}, old_value{has_old_value ? getenv(name) : ""} { if (value) setenv(name, value, overwrite); else unsetenv(name); } repowerd::test::TemporaryEnvironmentValue::~TemporaryEnvironmentValue() { if (has_old_value) setenv(name.c_str(), old_value.c_str(), overwrite); else unsetenv(name.c_str()); } repowerd-2023.07/tests/adapter-tests/temporary_environment_value.h000066400000000000000000000020551446034100200254470ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { namespace test { class TemporaryEnvironmentValue { public: TemporaryEnvironmentValue(char const* name, char const* value); ~TemporaryEnvironmentValue(); private: static int constexpr overwrite = 1; std::string const name; bool const has_old_value; std::string const old_value; }; } } repowerd-2023.07/tests/adapter-tests/temporary_file.cpp000066400000000000000000000027601446034100200231640ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "temporary_file.h" #include #include #include namespace rt = repowerd::test; rt::TemporaryFile::TemporaryFile() { char name_template[] = "/tmp/repowerd-test-XXXXXX"; fd = mkstemp(name_template); if (fd == -1) throw std::system_error{errno, std::system_category(), "Failed to create temporary file"}; filename = name_template; } rt::TemporaryFile::~TemporaryFile() { close(fd); unlink(filename.c_str()); } std::string rt::TemporaryFile::name() const { return filename; } void rt::TemporaryFile::write(std::string data) const { if (::write(fd, data.c_str(), data.size()) != static_cast(data.size())) throw std::system_error{errno, std::system_category(), "Failed to write to temporary file"}; fsync(fd); } repowerd-2023.07/tests/adapter-tests/temporary_file.h000066400000000000000000000017201446034100200226240ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { namespace test { class TemporaryFile { public: TemporaryFile(); ~TemporaryFile(); std::string name() const; void write(std::string data) const; private: int fd; std::string filename; }; } } repowerd-2023.07/tests/adapter-tests/test_android_autobrightness_algorithm.cpp000066400000000000000000000075151446034100200300140ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/android_autobrightness_algorithm.h" #include "src/adapters/event_loop.h" #include "fake_device_config.h" #include "fake_log.h" #include namespace rt = repowerd::test; using namespace testing; namespace { struct AnAndroidAutobrightnessAlgorithm : Test { AnAndroidAutobrightnessAlgorithm() { device_config_with_valid_curves.set("autoBrightnessLevels", "1,2,3"); device_config_with_valid_curves.set("autoBrightnessLcdBacklightValues", "1,2,3,4"); } void wait_for_event_loop_processing() { event_loop.enqueue([]{}).get(); } repowerd::EventLoop event_loop{"test"}; std::shared_ptr const fake_log{std::make_shared(repowerd::LogLevel::Debug)}; rt::FakeDeviceConfig device_config_with_valid_curves; }; } TEST_F(AnAndroidAutobrightnessAlgorithm, fails_to_initialize_without_autobrightness_curves) { rt::FakeDeviceConfig device_config_without_curves; repowerd::AndroidAutobrightnessAlgorithm ab_algorithm{ device_config_without_curves, fake_log}; EXPECT_FALSE(ab_algorithm.init(event_loop)); } TEST_F(AnAndroidAutobrightnessAlgorithm, fails_to_initialize_with_autobrightness_curves_of_incorrect_size) { rt::FakeDeviceConfig device_config_with_invalid_curves; device_config_with_invalid_curves.set("autoBrightnessLevels", "1,2,3"); device_config_with_invalid_curves.set("autoBrightnessLcdBacklightValues", "1,2,3"); repowerd::AndroidAutobrightnessAlgorithm ab_algorithm{ device_config_with_invalid_curves, fake_log}; EXPECT_FALSE(ab_algorithm.init(event_loop)); } TEST_F(AnAndroidAutobrightnessAlgorithm, initializes_with_autobrightness_curves_of_correct_size) { repowerd::AndroidAutobrightnessAlgorithm ab_algorithm{ device_config_with_valid_curves, fake_log}; EXPECT_TRUE(ab_algorithm.init(event_loop)); } TEST_F(AnAndroidAutobrightnessAlgorithm, reacts_immediately_to_first_light_value_after_started) { repowerd::AndroidAutobrightnessAlgorithm ab_algorithm{ device_config_with_valid_curves, fake_log}; ASSERT_TRUE(ab_algorithm.init(event_loop)); std::vector ab_values; auto const reg = ab_algorithm.register_autobrightness_handler( [&] (double brightness) { ab_values.push_back(brightness); }); ab_algorithm.start(); ab_algorithm.new_light_value(2.0); wait_for_event_loop_processing(); EXPECT_THAT(ab_values.size(), Eq(1)); } TEST_F(AnAndroidAutobrightnessAlgorithm, ignores_light_values_when_stopped) { repowerd::AndroidAutobrightnessAlgorithm ab_algorithm{ device_config_with_valid_curves, fake_log}; ASSERT_TRUE(ab_algorithm.init(event_loop)); std::vector ab_values; auto const reg = ab_algorithm.register_autobrightness_handler( [&] (double brightness) { ab_values.push_back(brightness); }); ab_algorithm.new_light_value(2.0); wait_for_event_loop_processing(); EXPECT_THAT(ab_values, IsEmpty()); ab_algorithm.start(); ab_algorithm.stop(); ab_algorithm.new_light_value(2.0); wait_for_event_loop_processing(); EXPECT_THAT(ab_values, IsEmpty()); } repowerd-2023.07/tests/adapter-tests/test_android_backlight.cpp000066400000000000000000000037571446034100200246410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/android_backlight.h" #include "fake_libhardware.h" #include #include using namespace testing; namespace { struct AnAndroidBacklight : Test { repowerd::test::FakeLibhardware fake_libhardware; std::unique_ptr create_backlight() { return std::make_unique(); } }; MATCHER_P(LightState, brightness, "") { return arg.flashMode == LIGHT_FLASH_NONE && arg.brightnessMode == BRIGHTNESS_MODE_USER && arg.color == ((0xffU << 24) | (brightness << 16) | (brightness << 8) | brightness); } } TEST_F(AnAndroidBacklight, opens_and_closes_lights_module) { EXPECT_THAT(fake_libhardware.is_lights_module_open(), Eq(false)); auto backlight = create_backlight(); EXPECT_THAT(fake_libhardware.is_lights_module_open(), Eq(true)); backlight.reset(); EXPECT_THAT(fake_libhardware.is_lights_module_open(), Eq(false)); } TEST_F(AnAndroidBacklight, sets_brightness) { auto const backlight = create_backlight(); backlight->set_brightness(0.0); backlight->set_brightness(0.5); backlight->set_brightness(1.0); EXPECT_THAT(fake_libhardware.backlight_state_history(), ElementsAre(LightState(0), LightState(128), LightState(255))); } repowerd-2023.07/tests/adapter-tests/test_android_device_config.cpp000066400000000000000000000147121446034100200254660ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/android_device_config.h" #include "fake_device_info.h" #include "fake_log.h" #include "fake_filesystem.h" #include #include #include using namespace testing; namespace rt = repowerd::test; namespace { char const* const config_default1 = R"( false 4 680 2 4 6 1 )"; char const* const config_default2 = R"( false 4 680 2 4 6 2 )"; char const* const config_device = R"( true 5 123 1 3 5 3 )"; struct AnAndroidDeviceConfig : Test { AnAndroidDeviceConfig() { fake_fs->add_file_with_contents("/configdir1/config-default.xml", config_default1); fake_fs->add_file_with_contents("/configdir1/config-device.xml", config_device); fake_fs->add_file_with_contents("/configdir2/config-default.xml", config_default2); } void set_device_name() { fake_device_info->set_name("device"); } std::shared_ptr fake_device_info{std::make_shared()}; std::shared_ptr fake_log{std::make_shared(repowerd::LogLevel::Debug)}; std::shared_ptr fake_fs{std::make_shared()}; std::string const config_dir_1{"/configdir1"}; std::string const config_dir_2{"/configdir2"}; std::string const config_dir_empty{"/configdirempty"}; rt::FakeFilesystem fs; }; } TEST_F(AnAndroidDeviceConfig, reads_default_config_file) { repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_THAT(config.get("boolconfig", ""), StrEq("false")); EXPECT_THAT(config.get("integerconfig", ""), StrEq("4")); EXPECT_THAT(config.get("integerconfigwithoutprefix", ""), StrEq("680")); EXPECT_THAT(config.get("integerarrayconfig", ""), StrEq("2,4,6")); } TEST_F(AnAndroidDeviceConfig, returns_default_value_for_unknown_key) { repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_THAT(config.get("unknown", "bla"), StrEq("bla")); } TEST_F(AnAndroidDeviceConfig, reads_first_default_config_file_from_config_dirs) { repowerd::AndroidDeviceConfig config{ fake_log, fake_fs, fake_device_info, {config_dir_empty, config_dir_2, config_dir_1}}; EXPECT_THAT(config.get("id", ""), StrEq("2")); } TEST_F(AnAndroidDeviceConfig, logs_config_files_read) { repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_TRUE(fake_log->contains_line({config_dir_1 + "/config-default.xml"})); } TEST_F(AnAndroidDeviceConfig, overwrites_value_from_default_with_device_specific) { set_device_name(); repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_THAT(config.get("boolconfig", ""), StrEq("true")); EXPECT_THAT(config.get("integerconfig", ""), StrEq("5")); EXPECT_THAT(config.get("integerarrayconfig", ""), StrEq("1,3,5")); } TEST_F(AnAndroidDeviceConfig, keeps_value_only_in_default_or_device_specific) { set_device_name(); repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_THAT(config.get("integerconfigwithoutprefix", ""), StrEq("680")); EXPECT_THAT(config.get("integerconfigwithoutprefixnew", ""), StrEq("123")); } TEST_F(AnAndroidDeviceConfig, logs_device_specific_file_path) { set_device_name(); repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_TRUE(fake_log->contains_line({config_dir_1 + "/config-default.xml"})); EXPECT_TRUE(fake_log->contains_line({config_dir_1 + "/config-device.xml"})); } TEST_F(AnAndroidDeviceConfig, logs_properties) { set_device_name(); repowerd::AndroidDeviceConfig config{fake_log, fake_fs, fake_device_info, {config_dir_1}}; EXPECT_TRUE(fake_log->contains_line({"Property", "boolconfig", "true"})); EXPECT_TRUE(fake_log->contains_line({"Property", "integerconfig", "5"})); EXPECT_TRUE(fake_log->contains_line({"Property", "integerarrayconfig", "1,3,5"})); EXPECT_TRUE(fake_log->contains_line({"Property", "integerconfigwithoutprefix", "680"})); EXPECT_TRUE(fake_log->contains_line({"Property", "integerconfigwithoutprefixnew", "123"})); } TEST_F(AnAndroidDeviceConfig, logs_config_dirs) { repowerd::AndroidDeviceConfig config{ fake_log, fake_fs, fake_device_info, {config_dir_1, config_dir_2, config_dir_empty}}; EXPECT_TRUE(fake_log->contains_line({"config", "directory", config_dir_1})); EXPECT_TRUE(fake_log->contains_line({"config", "directory", config_dir_2})); EXPECT_TRUE(fake_log->contains_line({"config", "directory", config_dir_empty})); } repowerd-2023.07/tests/adapter-tests/test_android_device_quirks.cpp000066400000000000000000000034751446034100200255430ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/android_device_quirks.h" #include "fake_device_info.h" #include "fake_log.h" #include "fake_filesystem.h" #include using namespace testing; namespace rt = repowerd::test; namespace { struct AnAndroidDeviceQuirks : Test { std::shared_ptr fake_device_info{std::make_shared()}; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; }; } TEST_F(AnAndroidDeviceQuirks, ignore_session_deactivation_is_false_if_device_is_desktop) { fake_device_info->set_is_desktop(true); repowerd::AndroidDeviceQuirks android_device_quirks{fake_log, fake_device_info}; EXPECT_FALSE(android_device_quirks.ignore_session_deactivation()); EXPECT_TRUE(fake_log.contains_line({"ignore_session_deactivation", "false"})); } TEST_F(AnAndroidDeviceQuirks, ignore_session_deactivation_is_true_if_device_is_not_desktop) { repowerd::AndroidDeviceQuirks android_device_quirks{fake_log, fake_device_info}; EXPECT_TRUE(android_device_quirks.ignore_session_deactivation()); EXPECT_TRUE(fake_log.contains_line({"ignore_session_deactivation", "true"})); } repowerd-2023.07/tests/adapter-tests/test_backlight_brightness_control.cpp000066400000000000000000000476141446034100200271310ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/autobrightness_algorithm.h" #include "src/adapters/backlight_brightness_control.h" #include "src/adapters/backlight.h" #include "src/adapters/event_loop_handler_registration.h" #include "src/adapters/light_sensor.h" #include "fake_chrono.h" #include "fake_device_config.h" #include "fake_device_quirks.h" #include "fake_log.h" #include "fake_shared.h" #include "spin_wait.h" #include #include #include #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { class FakeBacklight : public repowerd::Backlight { public: FakeBacklight(std::shared_ptr const& chrono) : chrono{chrono} { } void set_brightness(double v) override { brightness_history.push_back(v); // We have to fake-sleep here since the dimming code measures // actual execution time of this method chrono->sleep_for(2500us); } double get_brightness() override { return brightness_history.back(); } void clear_brightness_history() { auto const last = brightness_history.back(); brightness_history.clear(); brightness_history.push_back(last); } std::vector brightness_steps() { auto steps = brightness_history; std::adjacent_difference(steps.begin(), steps.end(), steps.begin()); steps.erase(steps.begin()); std::transform(steps.begin(), steps.end(), steps.begin(), [](auto s) { return std::fabs(s); }); return steps; } double brightness_steps_stddev() { auto const steps = brightness_steps(); auto const sum = std::accumulate(steps.begin(), steps.end(), 0.0); auto const mean = sum / steps.size(); auto accum = 0.0; for (auto const& d : steps) accum += (d - mean) * (d - mean); return sqrt(accum / (steps.size() - 1)); } double const starting_brightness = 0.5; std::vector brightness_history{starting_brightness}; std::shared_ptr const chrono; }; class FakeLightSensor : public repowerd::LightSensor { public: repowerd::HandlerRegistration register_light_handler( repowerd::LightHandler const& handler) override { light_handler = handler; return repowerd::HandlerRegistration( [this] { light_handler = [](double){}; }); } void enable_light_events() override { enabled = true; } void disable_light_events() override { enabled = false; } void emit_light_if_enabled(double light) { if (enabled) light_handler(light); } repowerd::LightHandler light_handler{[](double){}}; bool enabled{false}; }; class FakeAutobrightnessAlgorithm : public repowerd::AutobrightnessAlgorithm { public: bool init(repowerd::EventLoop& event_loop) override { this->event_loop = &event_loop; return true; } void new_light_value(double light) override { light_history.push_back(light); } void start() override { mock.start(); } void stop() override { mock.stop(); } struct MockMethods { MOCK_METHOD0(start, void()); MOCK_METHOD0(stop, void()); }; NiceMock mock; void emit_autobrightness(double brightness) { event_loop->enqueue([this,brightness] { autobrightness_handler(brightness); }).get(); } repowerd::HandlerRegistration register_autobrightness_handler( repowerd::AutobrightnessHandler const& handler) override { return repowerd::EventLoopHandlerRegistration( *event_loop, [this,&handler] { autobrightness_handler = handler; }, [this] { autobrightness_handler = [](double){}; }); } repowerd::EventLoop* event_loop; repowerd::AutobrightnessHandler autobrightness_handler{[](double){}}; std::vector light_history; }; struct ABacklightBrightnessControl : Test { void expect_brightness_value(double brightness) { EXPECT_THAT(backlight.brightness_history.back(), Eq(brightness)); } std::chrono::milliseconds fake_chrono_duration_of(std::function const& func) { auto start = fake_chrono.steady_now(); func(); return std::chrono::duration_cast( fake_chrono.steady_now() - start); } rt::FakeDeviceConfig fake_device_config; FakeLightSensor light_sensor; FakeAutobrightnessAlgorithm autobrightness_algorithm; rt::FakeChrono fake_chrono; FakeBacklight backlight{rt::fake_shared(fake_chrono)}; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeDeviceQuirks fake_device_quirks; repowerd::BacklightBrightnessControl brightness_control{ rt::fake_shared(backlight), rt::fake_shared(light_sensor), rt::fake_shared(autobrightness_algorithm), rt::fake_shared(fake_chrono), rt::fake_shared(fake_log), fake_device_config, fake_device_quirks}; double const normal_percent = static_cast(fake_device_config.brightness_default_value) / fake_device_config.brightness_max_value; double const dim_percent = static_cast(fake_device_config.brightness_dim_value) / fake_device_config.brightness_max_value; std::chrono::seconds default_timeout{3}; }; MATCHER_P(IsAbout, a, "") { return arg >= a - 10ms && arg <= a + 10ms; } } TEST_F(ABacklightBrightnessControl, writes_normal_brightness_based_on_device_config) { brightness_control.set_normal_brightness(); expect_brightness_value(normal_percent); } TEST_F(ABacklightBrightnessControl, writes_zero_brightness_value_for_off_brightness) { brightness_control.set_normal_brightness(); brightness_control.set_off_brightness(); expect_brightness_value(0); } TEST_F(ABacklightBrightnessControl, writes_default_dim_brightness_based_on_device_config) { brightness_control.set_dim_brightness(); expect_brightness_value(dim_percent); } TEST_F(ABacklightBrightnessControl, sets_write_normal_brightness_value_immediately_if_in_normal_mode) { brightness_control.set_normal_brightness(); brightness_control.set_normal_brightness_value(0.7); expect_brightness_value(0.7); } TEST_F(ABacklightBrightnessControl, does_not_write_new_normal_brightness_value_if_not_in_normal_mode) { brightness_control.set_off_brightness(); brightness_control.set_normal_brightness_value(0.7); expect_brightness_value(0); } TEST_F(ABacklightBrightnessControl, applies_set_normal_brightness_value_when_changing_to_normal_mode) { brightness_control.set_normal_brightness_value(0.7); brightness_control.set_normal_brightness(); expect_brightness_value(0.7); } TEST_F(ABacklightBrightnessControl, transitions_smoothly_between_brightness_values_when_increasing) { brightness_control.set_off_brightness(); brightness_control.set_normal_brightness(); EXPECT_THAT(backlight.brightness_history.size(), Ge(20)); EXPECT_THAT(backlight.brightness_steps_stddev(), Le(0.01)); } TEST_F(ABacklightBrightnessControl, transitions_smoothly_between_brightness_values_when_decreasing) { brightness_control.set_off_brightness(); brightness_control.set_normal_brightness(); backlight.clear_brightness_history(); brightness_control.set_off_brightness(); EXPECT_THAT(backlight.brightness_history.size(), Ge(20)); EXPECT_THAT(backlight.brightness_steps_stddev(), Le(0.01)); } TEST_F(ABacklightBrightnessControl, transitions_between_zero_and_non_zero_brightness_in_250ms) { brightness_control.set_off_brightness(); EXPECT_THAT(fake_chrono_duration_of([&]{brightness_control.set_normal_brightness();}), IsAbout(250ms)); EXPECT_THAT(fake_chrono_duration_of([&]{brightness_control.set_off_brightness();}), IsAbout(250ms)); EXPECT_THAT(fake_chrono_duration_of([&]{brightness_control.set_dim_brightness();}), IsAbout(250ms)); } TEST_F(ABacklightBrightnessControl, does_not_transition_to_dim_if_current_brightness_is_positive_but_lower_than_dim) { auto const half_dim_percent = dim_percent / 2.0; ASSERT_THAT(half_dim_percent, Lt(dim_percent)); backlight.set_brightness(half_dim_percent); brightness_control.set_dim_brightness(); expect_brightness_value(half_dim_percent); } TEST_F(ABacklightBrightnessControl, transitions_to_dim_if_current_brightness_is_zero) { backlight.set_brightness(0.0); brightness_control.set_dim_brightness(); expect_brightness_value(dim_percent); } TEST_F(ABacklightBrightnessControl, transitions_to_dim_if_current_brightness_is_unknown) { backlight.set_brightness(repowerd::Backlight::unknown_brightness); brightness_control.set_dim_brightness(); expect_brightness_value(dim_percent); } TEST_F(ABacklightBrightnessControl, disables_light_events_when_autobrightness_is_disabled) { light_sensor.emit_light_if_enabled(500.0); // BacklightBrightnessControl handles light events asynchronously, // so we need to allow some time for the request to be processed std::this_thread::sleep_for(100ms); EXPECT_THAT(autobrightness_algorithm.light_history.size(), Eq(0)); } TEST_F(ABacklightBrightnessControl, enables_light_events_when_autobrightness_enabled_while_in_normal_mode) { brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); light_sensor.emit_light_if_enabled(500.0); // BacklightBrightnessControl handles light events asynchronously, // so we need to allow some time for the request to be processed rt::spin_wait_for_condition_or_timeout( [&] { return autobrightness_algorithm.light_history.size() == 1; }, default_timeout); EXPECT_THAT(autobrightness_algorithm.light_history.size(), Eq(1)); } TEST_F(ABacklightBrightnessControl, enables_light_events_when_set_to_normal_mode_while_autobrightness_enabled) { brightness_control.enable_autobrightness(); brightness_control.set_normal_brightness(); light_sensor.emit_light_if_enabled(500.0); // BacklightBrightnessControl handles light events asynchronously, // so we need to allow some time for the request to be processed rt::spin_wait_for_condition_or_timeout( [&] { return autobrightness_algorithm.light_history.size() == 1; }, default_timeout); EXPECT_THAT(autobrightness_algorithm.light_history.size(), Eq(1)); } TEST_F(ABacklightBrightnessControl, updates_brightness_from_autobrightness_algorithm_when_enabled_while_in_normal_mode) { brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(0.7); expect_brightness_value(0.7); } TEST_F(ABacklightBrightnessControl, updates_brightness_from_autobrightness_algorithm_when_set_to_normal_mode_while_enabled) { brightness_control.enable_autobrightness(); brightness_control.set_normal_brightness(); autobrightness_algorithm.emit_autobrightness(0.7); expect_brightness_value(0.7); } TEST_F(ABacklightBrightnessControl, does_not_set_normal_brightness_when_set_to_normal_mode_if_autobrightness_enabled) { auto const prev_history_size = backlight.brightness_history.size(); brightness_control.enable_autobrightness(); brightness_control.set_normal_brightness(); EXPECT_THAT(backlight.brightness_history.size(), Eq(prev_history_size)); brightness_control.set_off_brightness(); brightness_control.set_normal_brightness(); expect_brightness_value(0.0); } TEST_F(ABacklightBrightnessControl, sets_normal_brightness_if_autobrightness_enabled_when_set_from_off_to_normal_mode_with_quirk) { fake_device_quirks.set_normal_before_display_on_autobrightness(true); repowerd::BacklightBrightnessControl quirked_brightness_control{ rt::fake_shared(backlight), rt::fake_shared(light_sensor), rt::fake_shared(autobrightness_algorithm), rt::fake_shared(fake_chrono), rt::fake_shared(fake_log), fake_device_config, fake_device_quirks}; quirked_brightness_control.enable_autobrightness(); quirked_brightness_control.set_normal_brightness(); quirked_brightness_control.set_off_brightness(); quirked_brightness_control.set_normal_brightness(); expect_brightness_value(normal_percent); } TEST_F(ABacklightBrightnessControl, ignores_brightness_from_autobrightness_algorithm_if_disabled) { brightness_control.set_normal_brightness(); autobrightness_algorithm.emit_autobrightness(0.7); expect_brightness_value(normal_percent); } TEST_F(ABacklightBrightnessControl, ignores_brightness_from_autobrightness_algorithm_if_not_in_normal_mode) { brightness_control.enable_autobrightness(); brightness_control.set_dim_brightness(); autobrightness_algorithm.emit_autobrightness(0.7); expect_brightness_value(dim_percent); } TEST_F(ABacklightBrightnessControl, disabling_autobrightness_restores_user_brightness_if_in_normal_mode) { brightness_control.set_normal_brightness(); brightness_control.set_normal_brightness_value(0.7); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(0.1); expect_brightness_value(0.1); brightness_control.disable_autobrightness(); expect_brightness_value(0.7); } TEST_F(ABacklightBrightnessControl, disabling_autobrightness_leaves_brightness_unchanged_if_not_in_normal_mode) { brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(0.7); expect_brightness_value(0.7); brightness_control.set_dim_brightness(); brightness_control.disable_autobrightness(); expect_brightness_value(dim_percent); } TEST_F(ABacklightBrightnessControl, normal_brightness_value_set_by_user_not_applied_if_autobrightness_is_enabled) { brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(0.7); brightness_control.set_normal_brightness_value(0.9); expect_brightness_value(0.7); } TEST_F(ABacklightBrightnessControl, starts_autobrightness_algorithm_when_first_enabling_autobrightness) { EXPECT_CALL(autobrightness_algorithm.mock, start()).Times(1); brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); brightness_control.enable_autobrightness(); Mock::VerifyAndClearExpectations(&autobrightness_algorithm.mock); } TEST_F(ABacklightBrightnessControl, stops_autobrightness_algorithm_when_first_disabling_autobrightness) { EXPECT_CALL(autobrightness_algorithm.mock, start()).Times(1); EXPECT_CALL(autobrightness_algorithm.mock, stop()).Times(1); brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); brightness_control.disable_autobrightness(); brightness_control.disable_autobrightness(); Mock::VerifyAndClearExpectations(&autobrightness_algorithm.mock); } TEST_F(ABacklightBrightnessControl, stops_autobrightness_algorithm_when_setting_off_brightness) { EXPECT_CALL(autobrightness_algorithm.mock, stop()).Times(1); brightness_control.set_off_brightness(); Mock::VerifyAndClearExpectations(&autobrightness_algorithm.mock); } TEST_F(ABacklightBrightnessControl, starts_autobrightness_algorithm_when_setting_normal_brightness_if_enabled) { EXPECT_CALL(autobrightness_algorithm.mock, start()).Times(1); brightness_control.enable_autobrightness(); brightness_control.set_normal_brightness(); Mock::VerifyAndClearExpectations(&autobrightness_algorithm.mock); } TEST_F(ABacklightBrightnessControl, applies_last_autobrightness_if_enabled_when_setting_normal_brightness_after_dim) { brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(0.9); brightness_control.set_dim_brightness(); expect_brightness_value(dim_percent); brightness_control.set_normal_brightness(); expect_brightness_value(0.9); } TEST_F(ABacklightBrightnessControl, notifies_of_brightness_change) { double notified_brightness{0.0}; auto const handler_registration = brightness_control.register_brightness_handler( [&](double brightness) { notified_brightness = brightness; }); brightness_control.set_normal_brightness(); brightness_control.set_normal_brightness_value(0.9); EXPECT_THAT(notified_brightness, Eq(0.9)); brightness_control.set_dim_brightness(); EXPECT_THAT(notified_brightness, Eq(dim_percent)); } TEST_F(ABacklightBrightnessControl, notifies_of_autobrightness_change) { double notified_brightness{0.0}; auto const handler_registration = brightness_control.register_brightness_handler( [&](double brightness) { notified_brightness = brightness; }); brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(0.9); EXPECT_THAT(notified_brightness, Eq(0.9)); } TEST_F(ABacklightBrightnessControl, does_not_notify_if_brightness_does_not_change) { double notified_brightness{-1.0}; auto const handler_registration = brightness_control.register_brightness_handler( [&](double brightness) { notified_brightness = brightness; }); expect_brightness_value(backlight.starting_brightness); brightness_control.set_normal_brightness(); brightness_control.set_normal_brightness_value(backlight.starting_brightness); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(backlight.starting_brightness); EXPECT_THAT(notified_brightness, Eq(-1.0)); } TEST_F(ABacklightBrightnessControl, logs_brightness_transition) { brightness_control.set_off_brightness(); EXPECT_TRUE(fake_log.contains_line( {std::to_string(normal_percent).substr(0, 4), "0.00", "transition time"})); EXPECT_TRUE(fake_log.contains_line( {std::to_string(normal_percent).substr(0, 4), "0.00", "done"})); } TEST_F(ABacklightBrightnessControl, does_not_log_null_brightness_transition) { brightness_control.set_normal_brightness(); EXPECT_FALSE(fake_log.contains_line({"steps"})); EXPECT_FALSE(fake_log.contains_line({"done"})); } TEST_F(ABacklightBrightnessControl, transitions_directly_to_new_value_if_current_is_unknown) { backlight.set_brightness(repowerd::Backlight::unknown_brightness); auto const prev_history_size = backlight.brightness_history.size(); brightness_control.set_dim_brightness(); EXPECT_THAT(backlight.brightness_history.size(), Eq(prev_history_size + 1)); expect_brightness_value(dim_percent); } TEST_F(ABacklightBrightnessControl, logs_autobrightness_values) { auto const autobrightness_value = 0.08; brightness_control.set_normal_brightness(); brightness_control.enable_autobrightness(); autobrightness_algorithm.emit_autobrightness(autobrightness_value); EXPECT_TRUE(fake_log.contains_line( {"autobrightness", "value", std::to_string(autobrightness_value).substr(0, 4)})); } repowerd-2023.07/tests/adapter-tests/test_brightness_params.cpp000066400000000000000000000041041446034100200247070ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/brightness_params.h" #include "fake_device_config.h" #include namespace rt = repowerd::test; using namespace testing; namespace { struct ABrightnessParams : Test { rt::FakeDeviceConfig device_config; }; } TEST_F(ABrightnessParams, uses_values_from_device_config) { auto const brightness_params = repowerd::BrightnessParams::from_device_config(device_config); EXPECT_THAT(brightness_params.dim_value, Eq(device_config.brightness_dim_value)); EXPECT_THAT(brightness_params.min_value, Eq(device_config.brightness_min_value)); EXPECT_THAT(brightness_params.max_value, Eq(device_config.brightness_max_value)); EXPECT_THAT(brightness_params.default_value, Eq(device_config.brightness_default_value)); EXPECT_THAT(brightness_params.autobrightness_supported, Eq(device_config.brightness_autobrightness_supported)); } TEST_F(ABrightnessParams, falls_back_to_sensible_values_if_config_entries_are_missing) { device_config.clear(); auto const brightness_params = repowerd::BrightnessParams::from_device_config(device_config); EXPECT_THAT(brightness_params.dim_value, Eq(10)); EXPECT_THAT(brightness_params.min_value, Eq(10)); EXPECT_THAT(brightness_params.max_value, Eq(255)); EXPECT_THAT(brightness_params.default_value, Eq(102)); EXPECT_THAT(brightness_params.autobrightness_supported, Eq(false)); } repowerd-2023.07/tests/adapter-tests/test_dbus_event_loop.cpp000066400000000000000000000031451446034100200243670ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/dbus_event_loop.h" #include "current_thread_name.h" #include #include using namespace testing; namespace rt = repowerd::test; TEST(ADBusEventLoop, sets_thread_name) { std::string const thread_name{"MyThreadName"}; repowerd::EventLoop event_loop{thread_name}; std::string event_loop_thread_name; event_loop.enqueue( [&] { event_loop_thread_name = rt::current_thread_name(); }).wait(); EXPECT_THAT(event_loop_thread_name, StrEq(thread_name)); } TEST(ADBusEventLoop, truncates_long_thread_name) { std::string const long_thread_name{"MyLongLongLongThreadName"}; repowerd::EventLoop event_loop{long_thread_name}; std::string event_loop_thread_name; event_loop.enqueue( [&] { event_loop_thread_name = rt::current_thread_name(); }).wait(); EXPECT_THAT(event_loop_thread_name, StrEq(long_thread_name.substr(0, 15))); } repowerd-2023.07/tests/adapter-tests/test_default_state_machine_options.cpp000066400000000000000000000072741446034100200272720ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/default_state_machine_options.h" #include "fake_device_info.h" #include "fake_log.h" #include using namespace testing; namespace rt = repowerd::test; namespace { std::string ms_to_str(std::chrono::milliseconds ms) { return std::to_string(ms.count()); } std::string bool_to_str(bool b) { return b ? "true" : "false"; } struct ADefaultStateMachineOptions : Test { std::shared_ptr fake_device_info{std::make_shared()}; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; }; } TEST_F(ADefaultStateMachineOptions, treat_power_button_as_user_activity_is_false_if_device_has_a_name) { repowerd::DefaultStateMachineOptions default_state_machine_options{fake_log, fake_device_info}; EXPECT_FALSE(default_state_machine_options.treat_power_button_as_user_activity()); } TEST_F(ADefaultStateMachineOptions, treat_power_button_as_user_activity_is_true_if_device_is_desktop) { fake_device_info->set_is_desktop(true); repowerd::DefaultStateMachineOptions default_state_machine_options{fake_log, fake_device_info}; EXPECT_TRUE(default_state_machine_options.treat_power_button_as_user_activity()); } TEST_F(ADefaultStateMachineOptions, logs_options) { repowerd::DefaultStateMachineOptions options{fake_log, fake_device_info}; EXPECT_TRUE(fake_log.contains_line( { "notification_expiration_timeout", ms_to_str(options.notification_expiration_timeout()) })); EXPECT_TRUE(fake_log.contains_line( { "power_button_long_press_timeout", ms_to_str(options.power_button_long_press_timeout()) })); EXPECT_TRUE(fake_log.contains_line( { "user_inactivity_normal_display_dim_duration", ms_to_str(options.user_inactivity_normal_display_dim_duration()) })); EXPECT_TRUE(fake_log.contains_line( { "user_inactivity_normal_display_off_timeout", ms_to_str(options.user_inactivity_normal_display_off_timeout()) })); EXPECT_TRUE(fake_log.contains_line( { "user_inactivity_normal_suspend_timeout", ms_to_str(options.user_inactivity_normal_suspend_timeout()) })); EXPECT_TRUE(fake_log.contains_line( { "user_inactivity_post_notification_display_off_timeout", ms_to_str(options.user_inactivity_post_notification_display_off_timeout()) })); EXPECT_TRUE(fake_log.contains_line( { "user_inactivity_reduced_display_off_timeout", ms_to_str(options.user_inactivity_reduced_display_off_timeout()) })); EXPECT_TRUE(fake_log.contains_line( { "treat_power_button_as_user_activity", bool_to_str(options.treat_power_button_as_user_activity()) })); EXPECT_TRUE(fake_log.contains_line( { "turn_on_display_at_startup", bool_to_str(options.turn_on_display_at_startup()) })); } repowerd-2023.07/tests/adapter-tests/test_dev_alarm_wakeup_service.cpp000066400000000000000000000201701446034100200262230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/dev_alarm_wakeup_service.h" #include "fake_filesystem.h" #include "fake_shared.h" #include #include #include #include #include #include using namespace testing; using namespace std::chrono_literals; namespace rt = repowerd::test; namespace { struct FakeDevAlarm { FakeDevAlarm(rt::FakeFilesystem& fake_fs) { fake_fs.add_file_ioctl( "/dev/alarm", [this](auto, auto cmd, auto arg) { if (cmd == ANDROID_ALARM_WAIT) { this->alarm_wait(); } else if (cmd == ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP)) { if (fail_on_next_alarm_set_) { fail_on_next_alarm_set_ = false; return -1; } this->alarm_set(static_cast(arg)); } return 0; }); } void fail_on_next_alarm_set() { fail_on_next_alarm_set_ = true; } void alarm_wait() { std::unique_lock lock{next_wakeup_tp_mutex}; while (now < next_wakeup_tp) { lock.unlock(); std::this_thread::sleep_for(10ms); lock.lock(); } next_wakeup_tp = std::chrono::system_clock::time_point::max(); } void alarm_set(timespec* ts) { using namespace std::chrono; std::lock_guard lock{next_wakeup_tp_mutex}; auto const duration = seconds{ts->tv_sec} + nanoseconds{ts->tv_nsec}; next_wakeup_tp = system_clock::time_point{duration_cast(duration)}; } void advance_time_by(std::chrono::system_clock::duration advance) { std::lock_guard lock{next_wakeup_tp_mutex}; now = now + advance; } std::chrono::system_clock::time_point system_now() { std::lock_guard lock{next_wakeup_tp_mutex}; return now; } std::mutex next_wakeup_tp_mutex; std::chrono::system_clock::time_point next_wakeup_tp; std::chrono::system_clock::time_point now; bool fail_on_next_alarm_set_ = false; }; struct ADevAlarmWakeupService : Test { ADevAlarmWakeupService() { handler_registration = wakeup_service.register_wakeup_handler( [this] (std::string const& cookie) { wakeup_handler(cookie); }); } void wakeup_handler(std::string const& cookie) { std::unique_lock lock{wakeup_mutex}; wakeup_time_points.push_back(fake_dev_alarm.system_now()); wakeup_cookies.push_back(cookie); wakeup_cv.notify_all(); } void wait_for_wakeups( std::vector const& cookies, std::vector const& time_points) { std::unique_lock lock{wakeup_mutex}; auto const result = wakeup_cv.wait_for( lock, 3s, [&] { return cookies == wakeup_cookies && time_points == wakeup_time_points;} ); if (!result) throw std::runtime_error("Timeout waiting for wakeups"); } rt::FakeFilesystem fake_fs; FakeDevAlarm fake_dev_alarm{fake_fs}; repowerd::DevAlarmWakeupService wakeup_service{rt::fake_shared(fake_fs)}; repowerd::HandlerRegistration handler_registration; std::mutex wakeup_mutex; std::condition_variable wakeup_cv; std::vector wakeup_cookies; std::vector wakeup_time_points; }; } TEST_F(ADevAlarmWakeupService, returns_different_cookies) { auto const tp1 = fake_dev_alarm.system_now() + 100ms; auto const tp2 = fake_dev_alarm.system_now() + 200ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); EXPECT_THAT(cookie1, StrNe("")); EXPECT_THAT(cookie2, StrNe("")); EXPECT_THAT(cookie1, StrNe(cookie2)); } TEST_F(ADevAlarmWakeupService, schedules_wakeup) { auto const tp = fake_dev_alarm.system_now() + 100ms; auto cookie = wakeup_service.schedule_wakeup_at(tp); fake_dev_alarm.advance_time_by(100ms); wait_for_wakeups({cookie}, {tp}); } TEST_F(ADevAlarmWakeupService, cancels_wakeup) { auto const tp = fake_dev_alarm.system_now() + 100ms; auto const cookie = wakeup_service.schedule_wakeup_at(tp); wakeup_service.cancel_wakeup(cookie); fake_dev_alarm.advance_time_by(100ms); wait_for_wakeups({}, {}); } TEST_F(ADevAlarmWakeupService, schedules_multiple_wakeups) { auto const tp1 = fake_dev_alarm.system_now() + 50ms; auto const tp2 = fake_dev_alarm.system_now() + 100ms; auto const tp3 = fake_dev_alarm.system_now() + 150ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); auto const cookie3 = wakeup_service.schedule_wakeup_at(tp3); fake_dev_alarm.advance_time_by(50ms); wait_for_wakeups({cookie1}, {tp1}); fake_dev_alarm.advance_time_by(50ms); wait_for_wakeups({cookie1, cookie2}, {tp1, tp2}); fake_dev_alarm.advance_time_by(50ms); wait_for_wakeups({cookie1, cookie2, cookie3}, {tp1, tp2, tp3}); } TEST_F(ADevAlarmWakeupService, cancels_one_of_many_wakeups) { auto const tp1 = fake_dev_alarm.system_now() + 50ms; auto const tp2 = fake_dev_alarm.system_now() + 100ms; auto const tp3 = fake_dev_alarm.system_now() + 150ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); auto const cookie3 = wakeup_service.schedule_wakeup_at(tp3); wakeup_service.cancel_wakeup(cookie2); fake_dev_alarm.advance_time_by(50ms); wait_for_wakeups({cookie1}, {tp1}); fake_dev_alarm.advance_time_by(100ms); wait_for_wakeups({cookie1, cookie3}, {tp1, tp3}); } TEST_F(ADevAlarmWakeupService, throws_if_cannot_open_dev_alarm_at_construction) { EXPECT_THROW({ rt::FakeFilesystem empty_fs; repowerd::DevAlarmWakeupService wakeup_service(rt::fake_shared(empty_fs)); }, std::exception); } TEST_F(ADevAlarmWakeupService, throws_if_cannot_set_dev_alarm_at_construction) { EXPECT_THROW({ rt::FakeFilesystem local_fake_fs; FakeDevAlarm local_fake_dev_alarm(local_fake_fs); local_fake_dev_alarm.fail_on_next_alarm_set(); repowerd::DevAlarmWakeupService wakeup_service(rt::fake_shared(local_fake_fs)); }, std::exception); } TEST_F(ADevAlarmWakeupService, throws_if_cannot_set_dev_alarm) { EXPECT_THROW({ fake_dev_alarm.fail_on_next_alarm_set(); wakeup_service.schedule_wakeup_at({}); }, std::exception); } TEST_F(ADevAlarmWakeupService, does_not_leak_memory_when_triggering) { auto const tp1 = fake_dev_alarm.system_now() + 100ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); fake_dev_alarm.advance_time_by(100ms); wait_for_wakeups({cookie1}, {tp1}); EXPECT_THAT(wakeup_service.num_stored_elements(), Eq(0)); } TEST_F(ADevAlarmWakeupService, does_not_leak_memory_when_cancelling) { auto const tp1 = fake_dev_alarm.system_now() + 50ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); wakeup_service.cancel_wakeup(cookie1); EXPECT_THAT(wakeup_service.num_stored_elements(), Eq(0)); } repowerd-2023.07/tests/adapter-tests/test_event_loop.cpp000066400000000000000000000055471446034100200233620ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/event_loop.h" #include "src/adapters/fd.h" #include "current_thread_name.h" #include "spin_wait.h" #include #include #include #include using namespace testing; namespace rt = repowerd::test; namespace { void wait_for_string_contents( std::string const& str, std::string const& expected, std::mutex& str_mutex) { auto const result = rt::spin_wait_for_condition_or_timeout( [&] { std::lock_guard lock{str_mutex}; return str == expected; }, std::chrono::seconds{3}); if (!result) throw std::runtime_error("Timeout waiting for string " + expected); } } TEST(AnEventLoop, sets_thread_name) { std::string const thread_name{"MyThreadName"}; repowerd::EventLoop event_loop{thread_name}; std::string event_loop_thread_name; event_loop.enqueue( [&] { event_loop_thread_name = rt::current_thread_name(); }).wait(); EXPECT_THAT(event_loop_thread_name, StrEq(thread_name)); } TEST(AnEventLoop, truncates_long_thread_name) { std::string const long_thread_name{"MyLongLongLongThreadName"}; repowerd::EventLoop event_loop{long_thread_name}; std::string event_loop_thread_name; event_loop.enqueue( [&] { event_loop_thread_name = rt::current_thread_name(); }).wait(); EXPECT_THAT(event_loop_thread_name, StrEq(long_thread_name.substr(0, 15))); } TEST(AnEventLoop, watches_fd) { int pipefd[2]; if (pipe(pipefd) < 0) throw std::system_error{errno, std::system_category(), "Failed to create pipefd"}; repowerd::Fd read_fd{pipefd[0]}; repowerd::Fd write_fd{pipefd[1]}; std::mutex data_mutex; std::string data; repowerd::EventLoop event_loop{"fd"}; event_loop.watch_fd( read_fd, [&] { int c = 0; if (read(read_fd, &c, 1)) {} std::lock_guard lock{data_mutex}; data += c; }); if (write(write_fd, "a", 1)) {} wait_for_string_contents(data, "a", data_mutex); if (write(write_fd, "b", 1)) {} wait_for_string_contents(data, "ab", data_mutex); } repowerd-2023.07/tests/adapter-tests/test_event_loop_timer.cpp000066400000000000000000000074231446034100200245550ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/event_loop_timer.h" #include "wait_condition.h" #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct AnEventLoopTimer : testing::Test { repowerd::EventLoopTimer timer; repowerd::HandlerRegistration const reg{ timer.register_alarm_handler( [this](repowerd::AlarmId id) { alarm_handler(id); })}; MOCK_METHOD1(alarm_handler, void(repowerd::AlarmId id)); }; } TEST_F(AnEventLoopTimer, gives_different_ids_to_active_alarms) { auto const id1 = timer.schedule_alarm_in(10s); auto const id2 = timer.schedule_alarm_in(10s); auto const id3 = timer.schedule_alarm_in(10s); EXPECT_THAT(id1, Ne(id2)); EXPECT_THAT(id1, Ne(id3)); EXPECT_THAT(id2, Ne(id3)); } TEST_F(AnEventLoopTimer, notifies_when_alarm_triggers) { auto const id = timer.schedule_alarm_in(100ms); rt::WaitCondition alarm_triggered; EXPECT_CALL(*this, alarm_handler(id)) .WillOnce(WakeUp(&alarm_triggered)); alarm_triggered.wait_for(120ms); EXPECT_TRUE(alarm_triggered.woken()); } TEST_F(AnEventLoopTimer, notifies_in_order_when_multiple_alarms_trigger) { auto const id1 = timer.schedule_alarm_in(100ms); auto const id2 = timer.schedule_alarm_in(110ms); auto const id3 = timer.schedule_alarm_in(120ms); auto const id4 = timer.schedule_alarm_in(130ms); rt::WaitCondition alarm_triggered; testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id1)); EXPECT_CALL(*this, alarm_handler(id2)); EXPECT_CALL(*this, alarm_handler(id3)); EXPECT_CALL(*this, alarm_handler(id4)) .WillOnce(WakeUp(&alarm_triggered)); alarm_triggered.wait_for(150ms); EXPECT_TRUE(alarm_triggered.woken()); } TEST_F(AnEventLoopTimer, does_not_notify_for_alarms_not_triggered) { auto const id1 = timer.schedule_alarm_in(50ms); auto const id2 = timer.schedule_alarm_in(100ms); auto const id3 = timer.schedule_alarm_in(10s); testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id1)); EXPECT_CALL(*this, alarm_handler(id2)); EXPECT_CALL(*this, alarm_handler(id3)).Times(0); std::this_thread::sleep_for(150ms); } TEST_F(AnEventLoopTimer, reports_current_now) { auto const wait = 100ms; auto const then = timer.now(); std::this_thread::sleep_for(wait); auto const now = timer.now(); EXPECT_THAT(now - then, Ge(wait)); EXPECT_THAT(now - then, Le(wait + 20ms)); } TEST_F(AnEventLoopTimer, does_not_notify_for_cancelled_alarms) { auto const id1 = timer.schedule_alarm_in(50ms); auto const id2 = timer.schedule_alarm_in(100ms); auto const id3 = timer.schedule_alarm_in(150ms); auto const id4 = timer.schedule_alarm_in(200ms); testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id1)); EXPECT_CALL(*this, alarm_handler(id2)).Times(0); EXPECT_CALL(*this, alarm_handler(id3)); EXPECT_CALL(*this, alarm_handler(id4)).Times(0); timer.cancel_alarm(id4); timer.cancel_alarm(id2); std::this_thread::sleep_for(250ms); } repowerd-2023.07/tests/adapter-tests/test_fd.cpp000066400000000000000000000054641446034100200215770ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/fd.h" #include #include #include #include #include #include #include using namespace testing; namespace { struct AFd : testing::Test { ~AFd() { for (auto const& kv : pipes) { close(kv.second); } } int open_fd() { int pipefd[2]; if (pipe2(pipefd, O_NONBLOCK) == -1) { throw std::system_error{ errno, std::system_category(), "Failed to create pipe"}; } pipes[pipefd[1]] = pipefd[0]; return pipefd[1]; } bool is_fd_closed(int fd) { auto const iter = pipes.find(fd); if (iter == pipes.end()) throw std::runtime_error{"Untracked fd"}; char c{0}; return read(iter->second, &c, 1) == 0; } std::unordered_map pipes; }; } TEST_F(AFd, destruction_closes_file) { int const fd = open_fd(); { repowerd::Fd rfd{fd}; EXPECT_FALSE(is_fd_closed(fd)); } EXPECT_TRUE(is_fd_closed(fd)); } TEST_F(AFd, does_not_close_invalid_file_on_destruction) { repowerd::Fd rfd{-1}; } TEST_F(AFd, move_construction_moves_fd) { int const fd = open_fd(); { repowerd::Fd rfd1{fd}; { repowerd::Fd rfd2{std::move(rfd1)}; EXPECT_FALSE(is_fd_closed(fd)); } EXPECT_TRUE(is_fd_closed(fd)); } } TEST_F(AFd, move_assignment_moves_fd) { int const fd = open_fd(); { repowerd::Fd rfd1{fd}; { repowerd::Fd rfd2{-1}; rfd2 = std::move(rfd1); EXPECT_FALSE(is_fd_closed(fd)); } EXPECT_TRUE(is_fd_closed(fd)); } } TEST_F(AFd, move_assignment_closes_target_fd) { int const fd1 = open_fd(); int const fd2 = open_fd(); repowerd::Fd rfd1{fd1}; repowerd::Fd rfd2{fd2}; rfd2 = std::move(rfd1); EXPECT_FALSE(is_fd_closed(fd1)); EXPECT_TRUE(is_fd_closed(fd2)); rfd2 = repowerd::Fd{-1}; EXPECT_TRUE(is_fd_closed(fd1)); EXPECT_TRUE(is_fd_closed(fd2)); } repowerd-2023.07/tests/adapter-tests/test_in_separate_process.h000066400000000000000000000017671446034100200247050ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once template using repowerd_test_alias = T; #define TEST_IN_SEPARATE_PROCESS(CODE) \ EXPECT_EXIT({ \ CODE \ this->~repowerd_test_alias::type>(); \ exit(HasFailure() ? 1 : 0); \ }, \ ExitedWithCode(0), "") repowerd-2023.07/tests/adapter-tests/test_logind_session_tracker.cpp000066400000000000000000000317221446034100200257340ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "dbus_client.h" #include "fake_device_quirks.h" #include "fake_filesystem.h" #include "fake_log.h" #include "fake_shared.h" #include "fake_logind.h" #include "wait_condition.h" #include "src/adapters/logind_session_tracker.h" #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct ALogindSessionTracker : testing::Test { enum class WithQuirk { none, ignore_session_deactivation }; ALogindSessionTracker() { fake_logind.add_session(session_id(0), "mir", session_pid(0), session_uid(0)); fake_logind.add_session(session_id(1), "mir", session_pid(1), session_uid(1)); fake_logind.activate_session(session_id(0)); use_logind_session_tracker(WithQuirk::none); } void use_logind_session_tracker(WithQuirk quirk) { registrations.clear(); active_session_history.clear(); removed_session_history.clear(); rt::FakeDeviceQuirks fake_device_quirks; if (quirk == WithQuirk::ignore_session_deactivation) fake_device_quirks.set_ignore_session_deactivation(true); logind_session_tracker = std::make_unique( rt::fake_shared(fake_filesystem), rt::fake_shared(fake_log), fake_device_quirks, bus.address()); registrations.push_back( logind_session_tracker->register_active_session_changed_handler( [this] (std::string const& session_id, repowerd::SessionType type) { { std::lock_guard lock{session_mutex}; active_session_history.emplace_back(session_id, type); } session_cv.notify_all(); mock_handlers.active_session_changed(session_id, type); })); registrations.push_back( logind_session_tracker->register_session_removed_handler( [this] (std::string const& session_id) { { std::lock_guard lock{session_mutex}; removed_session_history.push_back(session_id); } session_cv.notify_all(); mock_handlers.session_removed(session_id); })); logind_session_tracker->start_processing(); } std::string session_id(int i) { return "session" + std::to_string(i); } pid_t session_pid(int i) { return 100 + i; } uid_t session_uid(int i) { return 1000 + i; } void associate_pid_with_uid(pid_t pid, uid_t uid) { auto const uid_str = std::to_string(uid); fake_filesystem.add_file_with_contents( "/proc/" + std::to_string(pid) + "/status", "Uid: " + uid_str + " " + uid_str + " " + uid_str + " " + uid_str); } void wait_until_active_session_is(std::string const& session_id) { std::unique_lock lock{session_mutex}; auto const success = session_cv.wait_for( lock, default_timeout, [&] { return !active_session_history.empty() && active_session_history.back().first == session_id; }); if (!success) throw std::runtime_error{ "Timeout while waiting for " + session_id + " to become the active session"}; } void wait_until_active_session_is( std::string const& session_id, repowerd::SessionType session_type) { std::unique_lock lock{session_mutex}; auto const success = session_cv.wait_for( lock, default_timeout, [&] { return !active_session_history.empty() && active_session_history.back().first == session_id && active_session_history.back().second == session_type; }); if (!success) throw std::runtime_error{ "Timeout while waiting for " + session_id + " to become the active session"}; } void wait_until_activated_sessions_are(std::vector const& activated) { std::unique_lock lock{session_mutex}; auto const success = session_cv.wait_for( lock, default_timeout, [&] { std::vector active_session_id_history; for (auto const& s : active_session_history) active_session_id_history.push_back(s.first); return activated == active_session_id_history; }); if (!success) throw std::runtime_error{ "Timeout while waiting for activated sessions"}; } void wait_until_removed_sessions_are(std::vector const& removed) { std::unique_lock lock{session_mutex}; auto const success = session_cv.wait_for( lock, default_timeout, [&] { return removed_session_history == removed; }); if (!success) throw std::runtime_error{ "Timeout while waiting for removed sessions"}; } struct MockHandlers { MOCK_METHOD2(active_session_changed, void(std::string const&, repowerd::SessionType)); MOCK_METHOD1(session_removed, void(std::string const&)); }; testing::NiceMock mock_handlers; rt::DBusBus bus; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeFilesystem fake_filesystem; std::unique_ptr logind_session_tracker; rt::FakeLogind fake_logind{bus.address()}; std::vector registrations; std::chrono::seconds const default_timeout{3}; std::mutex session_mutex; std::condition_variable session_cv; std::vector> active_session_history; std::vector removed_session_history; }; } TEST_F(ALogindSessionTracker, notifies_of_active_session_at_startup) { wait_until_active_session_is(session_id(0)); } TEST_F(ALogindSessionTracker, notifies_of_change_in_active_session) { fake_logind.activate_session(session_id(1)); wait_until_active_session_is(session_id(1)); } TEST_F(ALogindSessionTracker, notifies_of_removal_of_tracked_session) { fake_logind.activate_session(session_id(1)); wait_until_active_session_is(session_id(1)); fake_logind.remove_session(session_id(0)); fake_logind.remove_session(session_id(1)); wait_until_removed_sessions_are({session_id(0), session_id(1)}); } TEST_F(ALogindSessionTracker, does_not_notify_of_removal_of_untracked_session) { wait_until_active_session_is(session_id(0)); fake_logind.remove_session(session_id(1)); fake_logind.remove_session(session_id(0)); wait_until_removed_sessions_are({session_id(0)}); } TEST_F(ALogindSessionTracker, notifies_of_session_deactivation) { fake_logind.deactivate_session(); wait_until_active_session_is( repowerd::invalid_session_id, repowerd::SessionType::RepowerdIncompatible); } TEST_F(ALogindSessionTracker, marks_mir_sessions_as_repowerd_compatible) { fake_logind.add_session(session_id(2), "mir", session_pid(2), session_uid(2)); fake_logind.activate_session(session_id(2)); wait_until_active_session_is(session_id(2), repowerd::SessionType::RepowerdCompatible); } TEST_F(ALogindSessionTracker, marks_non_mir_sessions_as_repowerd_incompatible) { fake_logind.add_session(session_id(2), "x11", session_pid(2), session_uid(2)); fake_logind.activate_session(session_id(2)); wait_until_active_session_is(session_id(2), repowerd::SessionType::RepowerdIncompatible); } TEST_F(ALogindSessionTracker, returns_session_id_for_pid_of_tracked_session) { fake_logind.activate_session(session_id(1)); EXPECT_THAT(logind_session_tracker->session_for_pid(session_pid(0)), StrEq(session_id(0))); EXPECT_THAT(logind_session_tracker->session_for_pid(session_pid(1)), StrEq(session_id(1))); } TEST_F(ALogindSessionTracker, returns_invalid_session_id_for_pid_of_untracked_session) { EXPECT_THAT(logind_session_tracker->session_for_pid(session_pid(1)), StrEq(repowerd::invalid_session_id)); } TEST_F(ALogindSessionTracker, returns_invalid_session_id_for_pid_belonging_to_inactive_session_user) { fake_logind.activate_session(session_id(1)); wait_until_active_session_is(session_id(1)); pid_t const pid = 667; associate_pid_with_uid(pid, session_uid(0)); EXPECT_THAT(logind_session_tracker->session_for_pid(pid), StrEq(repowerd::invalid_session_id)); } TEST_F(ALogindSessionTracker, returns_invalid_session_id_for_pid_belonging_to_unknown_user) { pid_t const pid = 667; associate_pid_with_uid(pid, 9999); EXPECT_THAT(logind_session_tracker->session_for_pid(pid), StrEq(repowerd::invalid_session_id)); } TEST_F(ALogindSessionTracker, returns_active_session_id_for_pid_belonging_to_active_session_user) { pid_t const pid = 667; associate_pid_with_uid(pid, session_uid(0)); EXPECT_THAT(logind_session_tracker->session_for_pid(pid), StrEq(session_id(0))); } TEST_F(ALogindSessionTracker, returns_active_session_id_for_pid_belonging_to_root) { pid_t const pid = 667; uid_t const root_uid = 0; associate_pid_with_uid(pid, root_uid); EXPECT_THAT(logind_session_tracker->session_for_pid(pid), StrEq(session_id(0))); } TEST_F(ALogindSessionTracker, notifies_of_same_session_activation_after_deactivation) { fake_logind.deactivate_session(); fake_logind.activate_session(session_id(0)); wait_until_activated_sessions_are( {session_id(0), repowerd::invalid_session_id, session_id(0)}); } TEST_F(ALogindSessionTracker, does_not_notify_of_same_session_activation) { fake_logind.activate_session(session_id(0)); fake_logind.activate_session(session_id(0)); fake_logind.activate_session(session_id(1)); fake_logind.activate_session(session_id(1)); wait_until_activated_sessions_are({session_id(0), session_id(1)}); } TEST_F(ALogindSessionTracker, with_quirk_does_not_notify_of_session_deactivation) { use_logind_session_tracker(WithQuirk::ignore_session_deactivation); fake_logind.deactivate_session(); fake_logind.activate_session(session_id(1)); wait_until_activated_sessions_are({session_id(0), session_id(1)}); } TEST_F(ALogindSessionTracker, with_quirk_does_not_notify_of_same_session_activation_after_deactivation) { use_logind_session_tracker(WithQuirk::ignore_session_deactivation); fake_logind.deactivate_session(); fake_logind.activate_session(session_id(0)); fake_logind.activate_session(session_id(1)); wait_until_activated_sessions_are({session_id(0), session_id(1)}); } TEST_F(ALogindSessionTracker, logs_active_session_at_startup) { EXPECT_TRUE(fake_log.contains_line({"track_session", session_id(0), "mir"})); EXPECT_TRUE(fake_log.contains_line({"activate_session", session_id(0)})); } TEST_F(ALogindSessionTracker, logs_change_in_active_session) { fake_logind.add_session(session_id(2), "x11", session_pid(2), session_uid(2)); fake_logind.activate_session(session_id(2)); wait_until_active_session_is(session_id(2)); EXPECT_TRUE(fake_log.contains_line({"track_session", session_id(2), "x11"})); EXPECT_TRUE(fake_log.contains_line({"activate_session", session_id(2)})); } TEST_F(ALogindSessionTracker, logs_session_deactivation) { fake_logind.deactivate_session(); wait_until_active_session_is(repowerd::invalid_session_id); EXPECT_TRUE(fake_log.contains_line({"deactivate_session"})); } TEST_F(ALogindSessionTracker, logs_tracked_session_removal) { wait_until_active_session_is(session_id(0)); fake_logind.remove_session(session_id(1)); fake_logind.remove_session(session_id(0)); wait_until_removed_sessions_are({session_id(0)}); EXPECT_TRUE(fake_log.contains_line({"remove_session", session_id(0)})); EXPECT_FALSE(fake_log.contains_line({"remove_session", session_id(1)})); } repowerd-2023.07/tests/adapter-tests/test_logind_system_power_control.cpp000066400000000000000000000222661446034100200270410ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "fake_log.h" #include "fake_shared.h" #include "fake_logind.h" #include "spin_wait.h" #include "src/adapters/logind_system_power_control.h" #include #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct ALogindSystemPowerControl : testing::Test { rt::DBusBus bus; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeLogind fake_logind{bus.address()}; std::unique_ptr system_power_control; ALogindSystemPowerControl() { use_logind_with_initial_block_inhibited(""); } void use_logind_with_initial_block_inhibited(std::string const& blocks) { registrations.clear(); suspend_block_notifications.clear(); fake_logind.set_block_inhibited(blocks); system_power_control = std::make_unique( rt::fake_shared(fake_log), bus.address()); registrations.push_back( system_power_control->register_system_allow_suspend_handler( [&](std::string const& id) { std::lock_guard lock{mutex}; suspend_block_notifications += "[allow]"; suspend_block_ids.push_back(id); })); registrations.push_back( system_power_control->register_system_disallow_suspend_handler( [&](std::string const& id) { std::lock_guard lock{mutex}; suspend_block_notifications += "[disallow]"; suspend_block_ids.push_back(id); })); system_power_control->start_processing(); } void expect_inhibitions(std::unordered_set const& inhibitions) { rt::spin_wait_for_condition_or_timeout( [&] { return fake_logind.active_inhibitions() == inhibitions; }, default_timeout); EXPECT_THAT(fake_logind.active_inhibitions(), ContainerEq(inhibitions)); } void expect_no_inhibitions() { rt::spin_wait_for_condition_or_timeout( [&] { return fake_logind.active_inhibitions().empty(); }, default_timeout); EXPECT_THAT(fake_logind.active_inhibitions(), IsEmpty()); } void expect_power_requests(std::string const& power_requests) { EXPECT_THAT(fake_logind.power_requests(), StrEq(power_requests)); } void expect_suspend_block_notifications(std::string const& notifications) { EXPECT_TRUE( rt::spin_wait_for_condition_or_timeout( [&] { std::lock_guard lock{mutex}; return suspend_block_notifications == notifications; }, default_timeout)); } std::string inhibition_name_for_id(std::string const& id) { return "sleep:idle,repowerd," + id + ",block"; } std::string idle_and_lid_inhibition_name() { return "idle:handle-lid-switch,repowerd,repowerd handles idle and lid,block"; } std::chrono::seconds const default_timeout{3}; std::vector registrations; std::mutex mutex; std::string suspend_block_notifications; std::vector suspend_block_ids; }; } TEST_F(ALogindSystemPowerControl, disallow_automatic_suspend_is_a_noop) { system_power_control->disallow_automatic_suspend("id1"); expect_no_inhibitions(); } TEST_F(ALogindSystemPowerControl, allow_automatic_suspend_is_a_noop) { system_power_control->allow_automatic_suspend("id1"); expect_no_inhibitions(); } TEST_F(ALogindSystemPowerControl, powers_off_system) { system_power_control->power_off(); expect_power_requests("[power-off:f]"); } TEST_F(ALogindSystemPowerControl, suspends_system_regardless_of_disallowances) { system_power_control->disallow_automatic_suspend("id1"); expect_power_requests(""); system_power_control->suspend(); expect_power_requests("[suspend:f]"); } TEST_F(ALogindSystemPowerControl, disallow_default_system_handlers_adds_inhibition) { expect_no_inhibitions(); system_power_control->disallow_default_system_handlers(); expect_inhibitions({idle_and_lid_inhibition_name()}); } TEST_F(ALogindSystemPowerControl, allow_default_system_handlers_removes_inhibition) { system_power_control->disallow_default_system_handlers(); system_power_control->allow_default_system_handlers(); expect_no_inhibitions(); } TEST_F(ALogindSystemPowerControl, notifies_of_system_resume) { std::atomic system_resume{false}; auto const system_resume_registration = system_power_control->register_system_resume_handler( [&] { system_resume = true; }); fake_logind.emit_prepare_for_sleep(false); rt::spin_wait_for_condition_or_timeout( [&] { return system_resume.load(); }, default_timeout); EXPECT_THAT(system_resume, Eq(true)); EXPECT_TRUE(fake_log.contains_line({"PrepareForSleep", "false"})); } TEST_F(ALogindSystemPowerControl, notifies_of_system_allow_suspend_at_startup) { auto const block_inhibited = "shutdown:handle-power-key"; use_logind_with_initial_block_inhibited(block_inhibited); EXPECT_THAT(suspend_block_notifications, StrEq("[allow]")); EXPECT_TRUE(fake_log.contains_line({"BlockInhibited", block_inhibited})); } TEST_F(ALogindSystemPowerControl, notifies_of_system_disallow_suspend_at_startup) { auto const block_inhibited = "shutdown:sleep:handle-power-key"; use_logind_with_initial_block_inhibited(block_inhibited); EXPECT_THAT(suspend_block_notifications, StrEq("[disallow]")); EXPECT_TRUE(fake_log.contains_line({"BlockInhibited", block_inhibited})); } TEST_F(ALogindSystemPowerControl, notifies_of_system_allow_suspend_once) { auto const block_inhibited_disallow = "shutdown:handle-power-key:sleep"; auto const block_inhibited_allow = "shutdown:handle-power-key:slee"; use_logind_with_initial_block_inhibited(block_inhibited_disallow); fake_logind.set_block_inhibited(block_inhibited_allow); fake_logind.set_block_inhibited(block_inhibited_allow); fake_logind.set_block_inhibited(block_inhibited_allow); expect_suspend_block_notifications("[disallow][allow]"); EXPECT_TRUE(fake_log.contains_line({"BlockInhibited", block_inhibited_allow})); } TEST_F(ALogindSystemPowerControl, notifies_of_system_disallow_suspend_once) { auto const block_inhibited_disallow = "sleep:shutdown:handle-power-key"; fake_logind.set_block_inhibited(block_inhibited_disallow); fake_logind.set_block_inhibited(block_inhibited_disallow); fake_logind.set_block_inhibited(block_inhibited_disallow); expect_suspend_block_notifications("[allow][disallow]"); EXPECT_TRUE(fake_log.contains_line({"BlockInhibited", block_inhibited_disallow})); } TEST_F(ALogindSystemPowerControl, system_allow_and_disallow_suspend_notifications_use_same_id) { auto const block_inhibited_disallow = "shutdown:handle-power-key:sleep"; auto const block_inhibited_allow = "sl"; fake_logind.set_block_inhibited(block_inhibited_disallow); expect_suspend_block_notifications("[allow][disallow]"); fake_logind.set_block_inhibited(block_inhibited_allow); expect_suspend_block_notifications("[allow][disallow][allow]"); std::lock_guard lock{mutex}; EXPECT_THAT(suspend_block_ids, Each(suspend_block_ids[0])); } TEST_F(ALogindSystemPowerControl, disallow_default_system_handlers_logs_inhibition) { system_power_control->disallow_default_system_handlers(); EXPECT_TRUE(fake_log.contains_line({"inhibit", "idle:handle-lid-switch"})); EXPECT_TRUE(fake_log.contains_line({"inhibit", "idle:handle-lid-switch", "done"})); } TEST_F(ALogindSystemPowerControl, allow_default_system_handlers_logs_inhibition_release) { system_power_control->allow_default_system_handlers(); EXPECT_TRUE(fake_log.contains_line({"releasing", "idle", "lid", "inhibition"})); } TEST_F(ALogindSystemPowerControl, power_off_is_logged) { system_power_control->power_off(); EXPECT_TRUE(fake_log.contains_line({"power_off"})); EXPECT_TRUE(fake_log.contains_line({"power_off", "done"})); } TEST_F(ALogindSystemPowerControl, suspend_is_logged) { system_power_control->suspend(); EXPECT_TRUE(fake_log.contains_line({"suspend"})); EXPECT_TRUE(fake_log.contains_line({"suspend", "done"})); } repowerd-2023.07/tests/adapter-tests/test_lsc_display.cpp000066400000000000000000000200251446034100200235020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "src/adapters/dbus_connection_handle.h" #include "src/adapters/dbus_event_loop.h" #include "src/adapters/lsc_display.h" #include "duration_of.h" #include "fake_log.h" #include "fake_shared.h" #include "spin_wait.h" #include "wait_condition.h" #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { char const* const lsc_display_service_introspection = R"( )"; class FakeLscDisplayDBusService { public: FakeLscDisplayDBusService(std::string const& bus_address) : dbus_connection{bus_address}, dbus_event_loop{"FakeLscDisplay"} { dbus_connection.request_name("com.lomiri.SystemCompositor.Display"); lsc_display_handler_registation = dbus_event_loop.register_object_handler( dbus_connection, "/com/lomiri/SystemCompositor/Display", lsc_display_service_introspection, [this] ( GDBusConnection* connection, gchar const* sender, gchar const* object_path, gchar const* interface_name, gchar const* method_name, GVariant* parameters, GDBusMethodInvocation* invocation) { dbus_method_call( connection, sender, object_path, interface_name, method_name, parameters, invocation); }); } void emit_active_outputs(int internal, int external) { this->internal = internal; this->external = external; g_dbus_connection_emit_signal( dbus_connection, nullptr, "/com/lomiri/SystemCompositor/Display", "org.freedesktop.DBus.Properties", "PropertiesChanged", g_variant_new_parsed( "(@s 'com.lomiri.SystemCompositor.Display'," " @a{sv} { 'ActiveOutputs' : <(%i,%i)> }," " @as [])", internal, external), nullptr); } struct MockDBusCalls { MOCK_METHOD1(turn_on, void(std::string const&)); MOCK_METHOD1(turn_off, void(std::string const&)); }; testing::NiceMock mock_dbus_calls; private: void dbus_method_call( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* method_name_cstr, GVariant* parameters, GDBusMethodInvocation* invocation) { std::string const method_name{method_name_cstr ? method_name_cstr : ""}; GVariant* reply{nullptr}; if (method_name == "TurnOn") { char const* filter{""}; g_variant_get(parameters, "(&s)", &filter); mock_dbus_calls.turn_on(filter); } else if (method_name == "TurnOff") { char const* filter{""}; g_variant_get(parameters, "(&s)", &filter); mock_dbus_calls.turn_off(filter); } else if (method_name == "Get") { reply = g_variant_new_parsed("(<(%i,%i)>,)", internal.load(), external.load()); } g_dbus_method_invocation_return_value(invocation, reply); } repowerd::DBusConnectionHandle dbus_connection; repowerd::DBusEventLoop dbus_event_loop; repowerd::HandlerRegistration lsc_display_handler_registation; std::atomic internal{0}; std::atomic external{0}; }; struct AnLscDisplay : testing::Test { void wait_for_have_external(repowerd::LscDisplay& lsc_display, bool value) { auto const result = rt::spin_wait_for_condition_or_timeout( [&] { return lsc_display.has_active_external_displays() == value; }, default_timeout); if (!result) { throw std::runtime_error( "Timeout while waiting for has_active_external_displays=" + std::to_string(value)); } } rt::DBusBus bus; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; FakeLscDisplayDBusService service{bus.address()}; repowerd::LscDisplay lsc_display{ rt::fake_shared(fake_log), bus.address()}; std::chrono::seconds const default_timeout{3}; }; } TEST_F(AnLscDisplay, turn_on_request_contacts_dbus_service) { rt::WaitCondition called; InSequence s; EXPECT_CALL(service.mock_dbus_calls, turn_on("all")); EXPECT_CALL(service.mock_dbus_calls, turn_on("internal")); EXPECT_CALL(service.mock_dbus_calls, turn_on("external")) .WillOnce(WakeUp(&called)); lsc_display.turn_on(repowerd::DisplayPowerControlFilter::all); lsc_display.turn_on(repowerd::DisplayPowerControlFilter::internal); lsc_display.turn_on(repowerd::DisplayPowerControlFilter::external); called.wait_for(default_timeout); EXPECT_TRUE(called.woken()); } TEST_F(AnLscDisplay, turn_off_request_contacts_dbus_service) { rt::WaitCondition called; InSequence s; EXPECT_CALL(service.mock_dbus_calls, turn_off("all")); EXPECT_CALL(service.mock_dbus_calls, turn_off("internal")); EXPECT_CALL(service.mock_dbus_calls, turn_off("external")) .WillOnce(WakeUp(&called)); lsc_display.turn_off(repowerd::DisplayPowerControlFilter::all); lsc_display.turn_off(repowerd::DisplayPowerControlFilter::internal); lsc_display.turn_off(repowerd::DisplayPowerControlFilter::external); called.wait_for(default_timeout); EXPECT_TRUE(called.woken()); } TEST_F(AnLscDisplay, handles_display_information_updates) { EXPECT_FALSE(lsc_display.has_active_external_displays()); service.emit_active_outputs(1, 1); wait_for_have_external(lsc_display, true); service.emit_active_outputs(1, 0); wait_for_have_external(lsc_display, false); } TEST_F(AnLscDisplay, queries_initial_display_information) { service.emit_active_outputs(1, 1); repowerd::LscDisplay local_lsc_display{ rt::fake_shared(fake_log), bus.address()}; wait_for_have_external(local_lsc_display, true); } TEST_F(AnLscDisplay, does_not_hang_waiting_for_initial_display_information_if_lsc_display_is_down) { rt::DBusBus empty_bus; repowerd::LscDisplay local_lsc_display{ rt::fake_shared(fake_log), empty_bus.address()}; } TEST_F(AnLscDisplay, waits_at_most_one_second_for_turn_on_response) { EXPECT_CALL(service.mock_dbus_calls, turn_on("all")) .WillOnce(InvokeWithoutArgs([]{ std::this_thread::sleep_for(1200ms); })); EXPECT_THAT( rt::duration_of( [this] { lsc_display.turn_on(repowerd::DisplayPowerControlFilter::all); }), AllOf(Ge(1000ms), Le(1100ms))); } TEST_F(AnLscDisplay, logs_turn_on_request) { lsc_display.turn_on(repowerd::DisplayPowerControlFilter::all); EXPECT_TRUE(fake_log.contains_line({"turn_on"})); } TEST_F(AnLscDisplay, logs_turn_off_request) { lsc_display.turn_off(repowerd::DisplayPowerControlFilter::all); EXPECT_TRUE(fake_log.contains_line({"turn_off"})); } repowerd-2023.07/tests/adapter-tests/test_lsc_power_button.cpp000066400000000000000000000107631446034100200245740ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "dbus_client.h" #include "src/adapters/lsc_power_button.h" #include "wait_condition.h" #include #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct LscPowerButtonDBusClient : rt::DBusClient { LscPowerButtonDBusClient(std::string const& dbus_address) : rt::DBusClient{ dbus_address, "com.lomiri.SystemCompositor.PowerButton", "/com/lomiri/SystemCompositor/PowerButton"} { connection.request_name("com.lomiri.SystemCompositor.PowerButton"); } void emit_power_button_press() { emit_signal("com.lomiri.SystemCompositor.PowerButton", "Press", nullptr); } void emit_power_button_release() { emit_signal("com.lomiri.SystemCompositor.PowerButton", "Release", nullptr); } repowerd::HandlerRegistration register_long_press_handler( std::function const& func) { return event_loop.register_signal_handler( connection, nullptr, "com.lomiri.SystemCompositor.PowerButton", "LongPress", "/com/lomiri/SystemCompositor/PowerButton", [func] ( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* /*signal_name*/, GVariant* /*parameters*/) { func(); }); } }; struct AnLscPowerButton : testing::Test { AnLscPowerButton() { registrations.push_back( lsc_power_button.register_power_button_handler( [this] (repowerd::PowerButtonState state) { mock_handlers.power_button(state); })); lsc_power_button.start_processing(); } struct MockHandlers { MOCK_METHOD1(power_button, void(repowerd::PowerButtonState)); }; testing::NiceMock mock_handlers; rt::DBusBus bus; repowerd::LscPowerButton lsc_power_button{bus.address()}; LscPowerButtonDBusClient client{bus.address()}; std::vector registrations; std::chrono::seconds const default_timeout{3}; }; } TEST_F(AnLscPowerButton, calls_handler_for_power_button_press_signal) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_button(repowerd::PowerButtonState::pressed)) .WillOnce(WakeUp(&request_processed)); client.emit_power_button_press(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnLscPowerButton, calls_handler_for_power_button_release_signal) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_button(repowerd::PowerButtonState::released)) .WillOnce(WakeUp(&request_processed)); client.emit_power_button_release(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnLscPowerButton, does_not_calls_unregistered_handlers) { using namespace testing; registrations.clear(); EXPECT_CALL(mock_handlers, power_button(_)).Times(0); client.emit_power_button_press(); client.emit_power_button_release(); // Give some time for dbus signals to be delivered std::this_thread::sleep_for(100ms); } TEST_F(AnLscPowerButton, emits_long_press_signal) { using namespace testing; std::promise promise; auto future = promise.get_future(); auto const reg = client.register_long_press_handler( [&promise] { promise.set_value(); }); lsc_power_button.notify_long_press(); EXPECT_THAT(future.wait_for(default_timeout), std::future_status::ready); } repowerd-2023.07/tests/adapter-tests/test_lsc_user_activity.cpp000066400000000000000000000071671446034100200247430ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "dbus_client.h" #include "src/adapters/lsc_user_activity.h" #include "wait_condition.h" #include #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct LscUserActivityDBusClient : rt::DBusClient { LscUserActivityDBusClient(std::string const& dbus_address) : rt::DBusClient{ dbus_address, "com.lomiri.SystemCompositor.UserActivity", "/com/lomiri/SystemCompositor/UserActivity"} { connection.request_name("com.lomiri.SystemCompositor.UserActivity"); } void emit_user_activity_changing_power_state() { emit_signal("com.lomiri.SystemCompositor.UserActivity", "Activity", g_variant_new("(i)", 0)); } void emit_user_activity_extending_power_state() { emit_signal("com.lomiri.SystemCompositor.UserActivity", "Activity", g_variant_new("(i)", 1)); } }; struct AnLscUserActivity : testing::Test { AnLscUserActivity() { registrations.push_back( lsc_user_activity.register_user_activity_handler( [this] (repowerd::UserActivityType type) { mock_handlers.user_activity(type); })); lsc_user_activity.start_processing(); } struct MockHandlers { MOCK_METHOD1(user_activity, void(repowerd::UserActivityType)); }; testing::NiceMock mock_handlers; rt::DBusBus bus; repowerd::LscUserActivity lsc_user_activity{bus.address()}; LscUserActivityDBusClient client{bus.address()}; std::vector registrations; std::chrono::seconds const default_timeout{3}; }; } TEST_F(AnLscUserActivity, calls_handler_for_user_activity_changing_power_state) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, user_activity(repowerd::UserActivityType::change_power_state)) .WillOnce(WakeUp(&request_processed)); client.emit_user_activity_changing_power_state(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnLscUserActivity, calls_handler_for_user_activity_extending_power_state) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, user_activity(repowerd::UserActivityType::extend_power_state)) .WillOnce(WakeUp(&request_processed)); client.emit_user_activity_extending_power_state(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnLscUserActivity, does_not_calls_unregistered_handlers) { using namespace testing; registrations.clear(); EXPECT_CALL(mock_handlers, user_activity(_)).Times(0); client.emit_user_activity_changing_power_state(); client.emit_user_activity_extending_power_state(); // Give some time for dbus signals to be delivered std::this_thread::sleep_for(100ms); } repowerd-2023.07/tests/adapter-tests/test_monotone_spline.cpp000066400000000000000000000051231446034100200244060ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/monotone_spline.h" #include using namespace testing; namespace { struct AMonotoneSpline : Test { std::vector const points{ {0.1, 3.0}, {0.2, 2.9}, {0.3, 2.5}, {0.4, 1.0}, {0.5, 0.9}, {0.6, 0.8}, {0.7, 0.5}, {0.8, 0.2}, {0.9, 0.1}}; int find_index(double x) { if (x < points[0].x) return -1; for (auto i = 0u; i < points.size() - 1; ++i) { if (x >= points[i].x && x < points[i+1].x) return i; } return points.size() - 1; } repowerd::MonotoneSpline const spline{points}; }; } TEST_F(AMonotoneSpline, returns_lowest_value_if_out_of_lower_bound) { EXPECT_THAT(spline.interpolate(0.09), Eq(points.front().y)); } TEST_F(AMonotoneSpline, returns_highest_value_if_out_of_upper_bound) { EXPECT_THAT(spline.interpolate(0.91), Eq(points.back().y)); } TEST_F(AMonotoneSpline, returns_original_points) { for (auto const& point : points) EXPECT_THAT(spline.interpolate(point.x), Eq(point.y)); } TEST_F(AMonotoneSpline, interpolated_points_lie_between_original_points) { for (auto x = 0.1; x < 0.9; x += 0.01) { auto i = find_index(x); auto y = spline.interpolate(x); auto min_y = points[i].y; auto max_y = points[i+1].y; if (min_y > max_y) { std::swap(min_y, max_y); EXPECT_THAT(y, Gt(min_y)); EXPECT_THAT(y, Le(max_y)); } else { EXPECT_THAT(y, Ge(min_y)); EXPECT_THAT(y, Lt(max_y)); } } } TEST_F(AMonotoneSpline, with_fewer_than_two_point_cannot_be_created) { EXPECT_THROW({ repowerd::MonotoneSpline({}); }, std::logic_error); EXPECT_THROW({ repowerd::MonotoneSpline({{1,1}}); }, std::logic_error); } repowerd-2023.07/tests/adapter-tests/test_ofono_voice_call_service.cpp000066400000000000000000000271561446034100200262300ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/ofono_voice_call_service.h" #include "dbus_bus.h" #include "fake_log.h" #include "fake_ofono.h" #include "fake_shared.h" #include "spin_wait.h" #include "wait_condition.h" #include #include #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; using namespace testing; namespace { auto modems_match_condition(rt::FakeOfono::Modems const& match) { return [match](rt::FakeOfono::Modems const& modems) { return match == modems; }; } auto modems_with_power( std::vector const& modems, rt::FakeOfono::ModemPowerState state) { rt::FakeOfono::Modems match; for (auto const& modem : modems) match[modem] = state; return modems_match_condition(match); } struct AnOfonoVoiceCallService : testing::Test { AnOfonoVoiceCallService() { registrations.push_back( ofono_voice_call_service.register_active_call_handler( [this] { mock_handlers.active_call(); })); registrations.push_back( ofono_voice_call_service.register_no_active_call_handler( [this] { mock_handlers.no_active_call(); })); ofono.add_modem(initial_modem); ofono_voice_call_service.start_processing(); } std::string call_path(int i) { return "/phonesim/call0" + std::to_string(i); } void wait_for_tracked_modems(std::unordered_set const& modems) { auto const result = rt::spin_wait_for_condition_or_timeout( [this,&modems] { return ofono_voice_call_service.tracked_modems() == modems; }, default_timeout); if (!result) throw std::runtime_error("Timeout while waiting for tracked modems"); } struct MockHandlers { MOCK_METHOD0(active_call, void()); MOCK_METHOD0(no_active_call, void()); }; testing::NiceMock mock_handlers; rt::DBusBus bus; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; repowerd::OfonoVoiceCallService ofono_voice_call_service{ rt::fake_shared(fake_log), bus.address()}; rt::FakeOfono ofono{bus.address()}; std::vector registrations; std::chrono::seconds const default_timeout{3}; std::string const initial_modem{"/phonesim"}; std::string const modem1{"/modem01"}; std::string const modem2{"/modem02"}; }; } TEST_F(AnOfonoVoiceCallService, calls_handler_for_new_active_calls) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, active_call()) .WillOnce(Return()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); ofono.add_call(call_path(1), repowerd::OfonoCallState::active); ofono.add_call(call_path(2), repowerd::OfonoCallState::alerting); ofono.add_call(call_path(3), repowerd::OfonoCallState::dialing); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnOfonoVoiceCallService, does_not_call_handler_for_new_inactive_calls) { EXPECT_CALL(mock_handlers, active_call()).Times(0); ofono.add_call(call_path(1), repowerd::OfonoCallState::disconnected); ofono.add_call(call_path(2), repowerd::OfonoCallState::held); ofono.add_call(call_path(3), repowerd::OfonoCallState::incoming); ofono.add_call(call_path(4), repowerd::OfonoCallState::waiting); // Give some time to requests to be processed std::this_thread::sleep_for(100ms); } TEST_F(AnOfonoVoiceCallService, calls_handler_for_no_active_call_when_call_removed) { rt::WaitCondition request_processed; ofono.add_call(call_path(1), repowerd::OfonoCallState::active); ofono.add_call(call_path(2), repowerd::OfonoCallState::active); ofono.add_call(call_path(3), repowerd::OfonoCallState::alerting); EXPECT_CALL(mock_handlers, no_active_call()).Times(0); ofono.remove_call(call_path(1)); ofono.remove_call(call_path(3)); // Give some time to requests to be processed std::this_thread::sleep_for(100ms); Mock::VerifyAndClearExpectations(&mock_handlers); EXPECT_CALL(mock_handlers, no_active_call()) .WillOnce(WakeUp(&request_processed)); ofono.remove_call(call_path(2)); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnOfonoVoiceCallService, calls_handler_for_active_call_when_call_state_changed) { ofono.add_call(call_path(1), repowerd::OfonoCallState::incoming); ofono.add_call(call_path(2), repowerd::OfonoCallState::held); rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, active_call()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); ofono.change_call_state(call_path(1), repowerd::OfonoCallState::active); ofono.change_call_state(call_path(2), repowerd::OfonoCallState::active); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnOfonoVoiceCallService, calls_handler_for_no_active_call_when_call_state_changed) { ofono.add_call(call_path(1), repowerd::OfonoCallState::active); ofono.add_call(call_path(2), repowerd::OfonoCallState::active); rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, no_active_call()) .WillOnce(WakeUp(&request_processed)); ofono.change_call_state(call_path(1), repowerd::OfonoCallState::held); ofono.change_call_state(call_path(2), repowerd::OfonoCallState::held); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AnOfonoVoiceCallService, sets_power_mode_on_initial_modems) { ofono_voice_call_service.set_low_power_mode(); auto condition = ofono.wait_for_modems_condition( modems_with_power( {initial_modem}, rt::FakeOfono::ModemPowerState::low), default_timeout); EXPECT_TRUE(condition); ofono_voice_call_service.set_normal_power_mode(); condition = ofono.wait_for_modems_condition( modems_with_power( {initial_modem}, rt::FakeOfono::ModemPowerState::normal), default_timeout); EXPECT_TRUE(condition); } TEST_F(AnOfonoVoiceCallService, sets_power_mode_on_modems_added_later) { ofono.add_modem(modem1); ofono.add_modem(modem2); auto all_modems = {initial_modem, modem1, modem2}; wait_for_tracked_modems(all_modems); ofono_voice_call_service.set_low_power_mode(); auto condition = ofono.wait_for_modems_condition( modems_with_power( all_modems, rt::FakeOfono::ModemPowerState::low), default_timeout); EXPECT_TRUE(condition); ofono_voice_call_service.set_normal_power_mode(); condition = ofono.wait_for_modems_condition( modems_with_power( all_modems, rt::FakeOfono::ModemPowerState::normal), default_timeout); EXPECT_TRUE(condition); } TEST_F(AnOfonoVoiceCallService, does_not_set_power_mode_on_removed_modems) { ofono.add_modem(modem1); ofono.add_modem(modem2); auto all_modems = {initial_modem, modem1, modem2}; auto all_modems_but_modem1 = {initial_modem, modem2}; wait_for_tracked_modems(all_modems); ofono.remove_modem(modem1); wait_for_tracked_modems(all_modems_but_modem1); ofono_voice_call_service.set_low_power_mode(); auto const condition = ofono.wait_for_modems_condition( modems_with_power( all_modems_but_modem1, rt::FakeOfono::ModemPowerState::low), default_timeout); EXPECT_TRUE(condition); } TEST_F(AnOfonoVoiceCallService, logs_call_added) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, active_call()) .WillOnce(Return()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); ofono.add_call(call_path(1), repowerd::OfonoCallState::active); ofono.add_call(call_path(2), repowerd::OfonoCallState::alerting); ofono.add_call(call_path(3), repowerd::OfonoCallState::dialing); request_processed.wait_for(default_timeout); EXPECT_TRUE(fake_log.contains_line({"CallAdded", call_path(1), "active"})); EXPECT_TRUE(fake_log.contains_line({"CallAdded", call_path(2), "alerting"})); EXPECT_TRUE(fake_log.contains_line({"CallAdded", call_path(3), "dialing"})); } TEST_F(AnOfonoVoiceCallService, logs_call_removed) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, active_call()); EXPECT_CALL(mock_handlers, no_active_call()) .WillOnce(WakeUp(&request_processed)); ofono.add_call(call_path(1), repowerd::OfonoCallState::active); ofono.remove_call(call_path(1)); request_processed.wait_for(default_timeout); EXPECT_TRUE(fake_log.contains_line({"CallRemoved", call_path(1)})); } TEST_F(AnOfonoVoiceCallService, logs_call_state_changed) { ofono.add_call(call_path(1), repowerd::OfonoCallState::incoming); rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, active_call()) .WillOnce(WakeUp(&request_processed)); ofono.change_call_state(call_path(1), repowerd::OfonoCallState::active); request_processed.wait_for(default_timeout); EXPECT_TRUE(fake_log.contains_line({"CallStateChanged", call_path(1), "active"})); } TEST_F(AnOfonoVoiceCallService, logs_existing_modems) { EXPECT_TRUE(fake_log.contains_line({"add_existing_modems", initial_modem})); } TEST_F(AnOfonoVoiceCallService, logs_modem_added) { ofono.add_modem(modem1); ofono.add_modem(modem2); auto all_modems = {initial_modem, modem1, modem2}; wait_for_tracked_modems(all_modems); EXPECT_TRUE(fake_log.contains_line({"ModemAdded", modem1})); EXPECT_TRUE(fake_log.contains_line({"ModemAdded", modem2})); } TEST_F(AnOfonoVoiceCallService, logs_modem_removed) { ofono.add_modem(modem1); ofono.add_modem(modem2); auto all_modems = {initial_modem, modem1, modem2}; auto all_modems_but_modem1 = {initial_modem, modem2}; wait_for_tracked_modems(all_modems); ofono.remove_modem(modem1); wait_for_tracked_modems(all_modems_but_modem1); EXPECT_TRUE(fake_log.contains_line({"ModemRemoved", modem1})); } TEST_F(AnOfonoVoiceCallService, logs_set_fast_dormancy) { ofono.add_modem(modem1); auto all_modems = {initial_modem, modem1}; wait_for_tracked_modems(all_modems); ofono_voice_call_service.set_low_power_mode(); ofono.wait_for_modems_condition( modems_with_power( all_modems, rt::FakeOfono::ModemPowerState::low), default_timeout); for (auto const& modem : all_modems) EXPECT_TRUE(fake_log.contains_line({"set_fast_dormancy", modem, "true"})); ofono_voice_call_service.set_normal_power_mode(); ofono.wait_for_modems_condition( modems_with_power( all_modems, rt::FakeOfono::ModemPowerState::normal), default_timeout); for (auto const& modem : all_modems) EXPECT_TRUE(fake_log.contains_line({"set_fast_dormancy", modem, "false"})); } repowerd-2023.07/tests/adapter-tests/test_path.cpp000066400000000000000000000022331446034100200221310ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/path.h" #include #include using namespace testing; namespace { struct APath : testing::Test { }; } TEST_F(APath, can_be_converted_to_string) { auto const path = repowerd::Path{"/dir"}; EXPECT_THAT(std::string{path}, Eq("/dir")); } TEST_F(APath, can_be_constructed_with_pathsep_operator) { auto const path = repowerd::Path{"/dir"}/"subdir1"; EXPECT_THAT(std::string{path}, Eq("/dir/subdir1")); } repowerd-2023.07/tests/adapter-tests/test_real_chrono.cpp000066400000000000000000000023041446034100200234670ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/real_chrono.h" #include "duration_of.h" #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct ARealChrono : Test { repowerd::RealChrono real_chrono; }; MATCHER_P(IsAbout, a, "") { return arg >= a - 10ms && arg <= a + 10ms; } } TEST_F(ARealChrono, sleeps_for_right_amount_of_time) { EXPECT_THAT(rt::duration_of([&]{real_chrono.sleep_for(50ms);}), IsAbout(50ms)); } repowerd-2023.07/tests/adapter-tests/test_real_filesystem.cpp000066400000000000000000000104621446034100200243670ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/real_filesystem.h" #include "src/adapters/fd.h" #include #include #include #include #include #include #include #include using namespace testing; namespace { struct TemporaryDirectory { TemporaryDirectory() { char dir_tmpl[] = "/tmp/repowerd-test-tmpdir-XXXXXX"; if (!mkdtemp(dir_tmpl)) throw std::system_error{errno, std::system_category()}; path = dir_tmpl; } ~TemporaryDirectory() { if (system((std::string{"rm -rf "} + path).c_str())) { std::cerr << "Failed to remove temp. dir " << path << std::endl; } } std::string path; }; struct ARealFilesystem : Test { ARealFilesystem() { mkdir_or_throw("/dir"); mkdir_or_throw("/dir/subdir1"); mkdir_or_throw("/dir/subdir2"); mkdir_or_throw("/dir1"); create_file_or_throw("/file", "abc"); symlink_or_throw("/dir1", "/dir/subdirlink"); symlink_or_throw("/file", "/dir1/filelink"); } void mkdir_or_throw(std::string const& path) { if (mkdir(full_path(path).c_str(), 0700) != 0) throw std::system_error{errno, std::system_category(), "Failed to mkdir"}; } void create_file_or_throw(std::string const& path, std::string const& contents) { std::ofstream fs{full_path(path)}; fs << contents; fs.flush(); } void symlink_or_throw(std::string const& to, std::string const& from) { if (symlink(full_path(to).c_str(), full_path(from).c_str()) != 0) { throw std::system_error{errno, std::system_category(), "Failed to symlink"}; } } std::string full_path(std::string const& path) { return temp_dir.path + path; } std::string file_contents(std::string const& path) { std::ifstream fs{full_path(path)}; std::string contents; fs >> contents; return contents; } TemporaryDirectory temp_dir; repowerd::RealFilesystem fs; }; } TEST_F(ARealFilesystem, recognizes_regular_file) { EXPECT_TRUE(fs.is_regular_file(full_path("/file"))); } TEST_F(ARealFilesystem, recognizes_regular_file_through_link) { EXPECT_TRUE(fs.is_regular_file(full_path("/dir1/filelink"))); } TEST_F(ARealFilesystem, does_not_recognizes_directory_as_regular_file) { EXPECT_FALSE(fs.is_regular_file(full_path("/dir"))); } TEST_F(ARealFilesystem, does_not_recognize_non_existent_path) { EXPECT_FALSE(fs.is_regular_file(full_path("/nonexistent"))); } TEST_F(ARealFilesystem, lists_subdirs) { auto const subdirs = fs.subdirs(full_path("/dir")); EXPECT_THAT(subdirs, UnorderedElementsAre( full_path("/dir/subdir1"), full_path("/dir/subdir2"), full_path("/dir/subdirlink"))); } TEST_F(ARealFilesystem, performs_ioctl) { auto const fd = fs.open(full_path("/file").c_str(), O_RDONLY); EXPECT_THAT(fd, Ge(0)); int bsz{0}; EXPECT_THAT(fs.ioctl(fd, FIGETBSZ, &bsz), Eq(0)); EXPECT_THAT(bsz, Gt(0)); } TEST_F(ARealFilesystem, reads_through_istream) { auto const istream = fs.istream(full_path("/file")); std::string contents; *istream >> contents; EXPECT_THAT(contents, StrEq("abc")); } TEST_F(ARealFilesystem, writes_through_ostream) { { auto const ostream = fs.ostream(full_path("/file")); std::string const new_contents{"123"}; *ostream << new_contents; } EXPECT_THAT(file_contents("/file"), StrEq("123")); } repowerd-2023.07/tests/adapter-tests/test_real_temporary_suspend_inhibition.cpp000066400000000000000000000052161446034100200302030ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/real_temporary_suspend_inhibition.h" #include "duration_of.h" #include "fake_shared.h" #include "fake_system_power_control.h" #include "spin_wait.h" #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct ARealTemporarySuspendInhibition : Test { rt::FakeSystemPowerControl fake_system_power_control; repowerd::RealTemporarySuspendInhibition real_temporary_suspend_inhbition{ rt::fake_shared(fake_system_power_control)}; bool is_automatic_suspend_allowed() { return fake_system_power_control.is_automatic_suspend_allowed(); } }; MATCHER_P(IsAbout, a, "") { return arg >= a - 10ms && arg <= a + 10ms; } } TEST_F(ARealTemporarySuspendInhibition, disallows_suspend) { real_temporary_suspend_inhbition.inhibit_suspend_for(100s, "bla"); EXPECT_FALSE(is_automatic_suspend_allowed()); } TEST_F(ARealTemporarySuspendInhibition, reallows_suspend_after_timeout) { EXPECT_THAT(rt::duration_of( [this] { real_temporary_suspend_inhbition.inhibit_suspend_for(50ms, "bla"); rt::spin_wait_for_condition_or_timeout( [this] { return is_automatic_suspend_allowed(); }, 3s); }), IsAbout(50ms)); } TEST_F(ARealTemporarySuspendInhibition, handles_concurrent_suspend_inhibitions) { EXPECT_THAT(rt::duration_of( [this] { real_temporary_suspend_inhbition.inhibit_suspend_for(100ms, "bla"); real_temporary_suspend_inhbition.inhibit_suspend_for(100ms, "bla1"); real_temporary_suspend_inhbition.inhibit_suspend_for(50ms, "bla"); real_temporary_suspend_inhbition.inhibit_suspend_for(50ms, "bla1"); rt::spin_wait_for_condition_or_timeout( [this] { return is_automatic_suspend_allowed(); }, 3s); }), IsAbout(100ms)); } repowerd-2023.07/tests/adapter-tests/test_repowerd_service.cpp000066400000000000000000000435251446034100200245550ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/dbus_connection_handle.h" #include "src/adapters/dbus_message_handle.h" #include "src/adapters/temporary_suspend_inhibition.h" #include "src/adapters/unity_screen_service.h" #include "dbus_bus.h" #include "dbus_client.h" #include "fake_brightness_notification.h" #include "fake_device_config.h" #include "fake_double_tap_to_wake.h" #include "fake_filesystem.h" #include "fake_log.h" #include "fake_wakeup_service.h" #include "fake_shared.h" #include "wait_condition.h" #include "spin_wait.h" #include #include #include #include using namespace testing; namespace rt = repowerd::test; namespace { char const* const repowerd_service_name = "com.lomiri.Repowerd"; char const* const repowerd_path = "/com/lomiri/Repowerd"; char const* const repowerd_interface = "com.lomiri.Repowerd"; struct MockTemporarySuspendInhibition : repowerd::TemporarySuspendInhibition { MOCK_METHOD2(inhibit_suspend_for, void(std::chrono::milliseconds,std::string const&)); }; struct RepowerdDBusClient : rt::DBusClient { RepowerdDBusClient(std::string const& dbus_address) : rt::DBusClient{ dbus_address, repowerd_service_name, repowerd_path} { } rt::DBusAsyncReplyString request_introspection() { return invoke_with_reply( "org.freedesktop.DBus.Introspectable", "Introspect", nullptr); } rt::DBusAsyncReplyString request_request_sys_state(int32_t state) { return invoke_with_reply( repowerd_interface, "requestSysState", g_variant_new("(si)", "test", state)); } rt::DBusAsyncReplyVoid request_clear_sys_state(std::string const& cookie) { return invoke_with_reply( repowerd_interface, "clearSysState", g_variant_new("(s)", cookie.c_str())); } rt::DBusAsyncReplyString request_request_wakeup( std::chrono::system_clock::time_point tp) { auto const t64 = static_cast(std::chrono::system_clock::to_time_t(tp)); return invoke_with_reply( repowerd_interface, "requestWakeup", g_variant_new("(st)", "test", t64)); } rt::DBusAsyncReplyVoid request_clear_wakeup(std::string const& cookie) { return invoke_with_reply( repowerd_interface, "clearWakeup", g_variant_new("(s)", cookie.c_str())); } rt::DBusAsyncReply request_get_brightness_params() { return invoke_with_reply( repowerd_interface, "getBrightnessParams", nullptr); } repowerd::HandlerRegistration register_wakeup_handler( std::function const& func) { return event_loop.register_signal_handler( connection, nullptr, repowerd_interface, "Wakeup", repowerd_path, [func] ( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* /*signal_name*/, GVariant* /*parameters*/) { func(); }); } repowerd::HandlerRegistration register_brightness_handler( std::function const& func) { return event_loop.register_signal_handler( connection, nullptr, "org.freedesktop.DBus.Properties", "PropertiesChanged", repowerd_path, [func, this] ( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* /*signal_name*/, GVariant* parameters) { char const* interface_name{""}; GVariantIter* changed_properties; GVariantIter* invalid_properties; g_variant_get(parameters, "(&sa{sv}as)", &interface_name, &changed_properties, &invalid_properties); auto const brightness = get_brightness_property(changed_properties); g_variant_iter_free(changed_properties); g_variant_iter_free(invalid_properties); if (brightness >= 0) func(brightness); }); } int32_t get_brightness_property(GVariantIter* properties) { char const* prop_name_cstr{""}; GVariant* prop_value{nullptr}; int32_t brightness = -1; bool done = false; while (!done && g_variant_iter_next(properties, "{&sv}", &prop_name_cstr, &prop_value)) { std::string const prop_name{prop_name_cstr ? prop_name_cstr : ""}; if (prop_name == "brightness") { brightness = g_variant_get_int32(prop_value); done = true; } g_variant_unref(prop_value); } return brightness; } }; struct APowerdService : testing::Test { APowerdService() { registrations.push_back( unity_screen_service.register_allow_suspend_handler( [this](auto id, auto pid){ mock_handlers.allow_suspend(id, pid); })); registrations.push_back( unity_screen_service.register_disallow_suspend_handler( [this](auto id, auto pid) { mock_handlers.disallow_suspend(id, pid); })); unity_screen_service.start_processing(); } struct MockHandlers { MOCK_METHOD2(allow_suspend, void(std::string const&, pid_t)); MOCK_METHOD2(disallow_suspend, void(std::string const&, pid_t)); }; testing::NiceMock mock_handlers; static int constexpr active_state{1}; std::chrono::seconds const default_timeout{3}; rt::DBusBus bus; rt::FakeBrightnessNotification fake_brightness_notification; rt::FakeDeviceConfig fake_device_config; rt::FakeFilesystem fake_filesystem; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeWakeupService fake_wakeup_service; rt::FakeDoubleTapToWake fake_double_tap_to_wake{ rt::fake_shared(fake_log), rt::fake_shared(fake_filesystem)}; NiceMock mock_temporary_suspend_inhibition; repowerd::UnityScreenService unity_screen_service{ rt::fake_shared(fake_wakeup_service), rt::fake_shared(fake_brightness_notification), rt::fake_shared(fake_log), rt::fake_shared(mock_temporary_suspend_inhibition), rt::fake_shared(fake_double_tap_to_wake), fake_device_config, bus.address()}; RepowerdDBusClient client{bus.address()}; std::vector registrations; }; ACTION_P(AppendArg0To, dst) { return dst->push_back(arg0); } } TEST_F(APowerdService, replies_to_introspection_request) { auto reply = client.request_introspection().get(); EXPECT_THAT(reply, StrNe("")); } TEST_F(APowerdService, forwards_request_sys_state_request) { EXPECT_CALL(mock_handlers, disallow_suspend(_, _)); client.request_request_sys_state(active_state).get(); } TEST_F(APowerdService, returns_different_cookies_for_request_sys_state_requests) { auto cookie1 = client.request_request_sys_state(active_state).get(); auto cookie2 = client.request_request_sys_state(active_state).get(); EXPECT_THAT(cookie1, StrNe("")); EXPECT_THAT(cookie2, StrNe("")); EXPECT_THAT(cookie1, StrNe(cookie2)); } TEST_F(APowerdService, returns_error_for_invalid_request_sys_state_request) { auto const invalid_state = 0; auto cookie = client.request_request_sys_state(invalid_state); auto reply_msg = static_cast(cookie).get(); EXPECT_THAT(g_dbus_message_get_message_type(reply_msg), Eq(G_DBUS_MESSAGE_TYPE_ERROR)); } TEST_F(APowerdService, allows_suspend_for_clear_sys_state_request) { std::string id_disallow; std::string id_allow; InSequence s; EXPECT_CALL(mock_handlers, disallow_suspend(_, _)) .WillOnce(SaveArg<0>(&id_disallow)); EXPECT_CALL(mock_handlers, allow_suspend(_, _)) .WillOnce(SaveArg<0>(&id_allow)); auto reply1 = client.request_request_sys_state(active_state); client.request_clear_sys_state(reply1.get()); EXPECT_THAT(id_allow, Eq(id_disallow)); } TEST_F(APowerdService, allows_suspend_for_multiple_clear_sys_state_requests) { std::vector id_disallow; std::vector id_allow; EXPECT_CALL(mock_handlers, disallow_suspend(_, _)) .Times(3).WillRepeatedly(AppendArg0To(&id_disallow)); EXPECT_CALL(mock_handlers, allow_suspend(_, _)) .Times(2).WillRepeatedly(AppendArg0To(&id_allow)); auto reply1 = client.request_request_sys_state(active_state); auto reply2 = client.request_request_sys_state(active_state); auto reply3 = client.request_request_sys_state(active_state); client.request_clear_sys_state(reply1.get()); client.request_clear_sys_state(reply2.get()); auto id3 = reply3.get(); Mock::VerifyAndClearExpectations(&mock_handlers); EXPECT_CALL(mock_handlers, allow_suspend(_, _)) .WillOnce(AppendArg0To(&id_allow)); client.request_clear_sys_state(id3); EXPECT_THAT(id_allow, ContainerEq(id_disallow)); } TEST_F(APowerdService, removes_all_client_suspend_disallowances_when_client_disconnects) { std::vector id_disallow; std::vector id_allow; rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, disallow_suspend(_, _)) .Times(3).WillRepeatedly(AppendArg0To(&id_disallow)); EXPECT_CALL(mock_handlers, allow_suspend(_, _)) .WillOnce(AppendArg0To(&id_allow)) .WillOnce(AppendArg0To(&id_allow)) .WillOnce(DoAll(AppendArg0To(&id_allow), WakeUp(&request_processed))); client.request_request_sys_state(active_state); client.request_request_sys_state(active_state); client.request_request_sys_state(active_state); client.disconnect(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_THAT(id_allow, UnorderedElementsAreArray(id_disallow)); } TEST_F(APowerdService, ignores_invalid_clear_sys_state_request) { std::string const invalid_cookie{"aaa"}; EXPECT_CALL(mock_handlers, allow_suspend(_, _)).Times(0); client.request_clear_sys_state(invalid_cookie).get(); } TEST_F(APowerdService, ignores_disconnects_from_clients_without_sys_state_request) { EXPECT_CALL(mock_handlers, allow_suspend(_, _)).Times(0); client.disconnect(); // Allow some time for disconnect notification to reach us std::this_thread::sleep_for(std::chrono::milliseconds(100)); } TEST_F(APowerdService, schedules_wakeup) { auto const tp = std::chrono::system_clock::from_time_t(12345); client.request_request_wakeup(tp).get(); EXPECT_THAT(fake_wakeup_service.emit_next_wakeup(), Eq(tp)); } TEST_F(APowerdService, emits_wakeup_signal) { auto const tp = std::chrono::system_clock::from_time_t(12345); std::promise wakeup_promise; auto wakeup_future = wakeup_promise.get_future(); auto const reg = client.register_wakeup_handler([&] { wakeup_promise.set_value(); }); client.request_request_wakeup(tp).get(); fake_wakeup_service.emit_next_wakeup(); EXPECT_THAT(wakeup_future.wait_for(default_timeout), Eq(std::future_status::ready)); } TEST_F(APowerdService, clears_wakeup) { auto const tp = std::chrono::system_clock::from_time_t(12345); std::promise wakeup_promise; auto wakeup_future = wakeup_promise.get_future(); auto const reg = client.register_wakeup_handler([&] { wakeup_promise.set_value(); }); auto const cookie = client.request_request_wakeup(tp).get(); client.request_clear_wakeup(cookie).get(); fake_wakeup_service.emit_next_wakeup(); EXPECT_THAT(wakeup_future.wait_for(std::chrono::milliseconds{100}), Eq(std::future_status::timeout)); } TEST_F(APowerdService, inhibits_suspend_temporarily_when_wakeup_is_triggered) { auto const tp = std::chrono::system_clock::from_time_t(12345); client.request_request_wakeup(tp).get(); auto const inhibition_timeout = std::chrono::milliseconds{3000}; EXPECT_CALL(mock_temporary_suspend_inhibition, inhibit_suspend_for(inhibition_timeout, _)); fake_wakeup_service.emit_next_wakeup(); } TEST_F(APowerdService, replies_to_get_brightness_params_request) { auto params = client.request_get_brightness_params().get(); auto body = g_dbus_message_get_body(params); int32_t dim_value; int32_t min_value; int32_t max_value; int32_t default_value; gboolean autobrightness_supported; g_variant_get( body, "((iiiib))", &dim_value, &min_value, &max_value, &default_value, &autobrightness_supported); EXPECT_THAT(dim_value, Eq(fake_device_config.brightness_dim_value)); EXPECT_THAT(min_value, Eq(fake_device_config.brightness_min_value)); EXPECT_THAT(max_value, Eq(fake_device_config.brightness_max_value)); EXPECT_THAT(default_value, Eq(fake_device_config.brightness_default_value)); EXPECT_THAT(autobrightness_supported, Eq(fake_device_config.brightness_autobrightness_supported)); } TEST_F(APowerdService, emits_brightness_property_change) { std::promise brightness_promise; auto brightness_future = brightness_promise.get_future(); auto const reg = client.register_brightness_handler( [&](int32_t brightness) { brightness_promise.set_value(brightness); }); fake_brightness_notification.emit_brightness(0.7); ASSERT_THAT(brightness_future.wait_for(default_timeout), Eq(std::future_status::ready)); EXPECT_THAT(brightness_future.get(), Eq(round(0.7 * fake_device_config.brightness_max_value))); } TEST_F(APowerdService, logs_request_sys_state_request) { auto const cookie = client.request_request_sys_state(active_state).get(); EXPECT_TRUE( fake_log.contains_line({ "requestSysState", "test", std::to_string(active_state), client.unique_name(), cookie})); } TEST_F(APowerdService, logs_clear_sys_state_request) { auto const cookie = client.request_request_sys_state(active_state).get(); client.request_clear_sys_state(cookie).get(); EXPECT_TRUE( fake_log.contains_line({ "clearSysState", client.unique_name(), cookie})); } TEST_F(APowerdService, logs_request_wakeup_request) { auto const tp = std::chrono::system_clock::from_time_t(12345); auto const cookie = client.request_request_wakeup(tp).get(); EXPECT_TRUE( fake_log.contains_line({ "requestWakeup", client.unique_name(), "test", cookie, std::to_string(std::chrono::system_clock::to_time_t(tp))})); } TEST_F(APowerdService, logs_clear_wakeup_request) { auto const tp = std::chrono::system_clock::from_time_t(12345); auto const cookie = client.request_request_wakeup(tp).get(); client.request_clear_wakeup(cookie).get(); EXPECT_TRUE( fake_log.contains_line({ "clearWakeup", client.unique_name(), cookie})); } TEST_F(APowerdService, logs_get_brightness_params) { client.request_get_brightness_params().get(); EXPECT_TRUE( fake_log.contains_line({ "getBrightnessParams", std::to_string(fake_device_config.brightness_dim_value), std::to_string(fake_device_config.brightness_min_value), std::to_string(fake_device_config.brightness_max_value), std::to_string(fake_device_config.brightness_default_value), fake_device_config.brightness_autobrightness_supported ? "true" : "false" })); } TEST_F(APowerdService, logs_wakeup_signal) { auto const tp = std::chrono::system_clock::from_time_t(12345); std::promise wakeup_promise; auto wakeup_future = wakeup_promise.get_future(); auto const reg = client.register_wakeup_handler([&] { wakeup_promise.set_value(); }); client.request_request_wakeup(tp).get(); fake_wakeup_service.emit_next_wakeup(); EXPECT_THAT(wakeup_future.wait_for(default_timeout), Eq(std::future_status::ready)); EXPECT_TRUE(fake_log.contains_line({"emit", "Wakeup"})); } TEST_F(APowerdService, logs_brightness_signal) { double const brightness = 0.7; std::promise brightness_promise; auto brightness_future = brightness_promise.get_future(); auto const reg = client.register_brightness_handler( [&](int32_t) { brightness_promise.set_value(); }); fake_brightness_notification.emit_brightness(brightness); ASSERT_THAT(brightness_future.wait_for(default_timeout), Eq(std::future_status::ready)); EXPECT_TRUE( fake_log.contains_line({ "emit", "brightness", std::to_string(brightness), std::to_string( static_cast(round(brightness * fake_device_config.brightness_max_value))) })); } repowerd-2023.07/tests/adapter-tests/test_repowerd_settings_service.cpp000066400000000000000000000273401446034100200264720ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/repowerd_settings_service.h" #include "src/core/infinite_timeout.h" #include "dbus_bus.h" #include "fake_log.h" #include "fake_shared.h" #include "repowerd_settings_dbus_client.h" #include #include #include using namespace testing; using namespace std::chrono_literals; namespace rt = repowerd::test; namespace { template struct PowerArg { T value; std::string str; }; struct ARepowerdSettingsService : testing::Test { ARepowerdSettingsService() { registrations.push_back( service.register_set_inactivity_behavior_handler( [this] (repowerd::PowerAction power_action, repowerd::PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid) { mock_handlers.set_inactivity_behavior( power_action, power_supply, timeout, pid); })); registrations.push_back( service.register_set_lid_behavior_handler( [this] (repowerd::PowerAction power_action, repowerd::PowerSupply power_supply, pid_t pid) { mock_handlers.set_lid_behavior( power_action, power_supply, pid); })); registrations.push_back( service.register_set_critical_power_behavior_handler( [this] (repowerd::PowerAction power_action, pid_t pid) { mock_handlers.set_critical_power_behavior( power_action, pid); })); service.start_processing(); } struct MockHandlers { MOCK_METHOD4(set_inactivity_behavior, void(repowerd::PowerAction power_action, repowerd::PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid)); MOCK_METHOD3(set_lid_behavior, void(repowerd::PowerAction power_action, repowerd::PowerSupply power_supply, pid_t pid)); MOCK_METHOD2(set_critical_power_behavior, void(repowerd::PowerAction power_action, pid_t pid)); }; testing::NiceMock mock_handlers; rt::DBusBus bus; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; repowerd::RepowerdSettingsService service{ rt::fake_shared(fake_log), bus.address()}; rt::RepowerdSettingsDBusClient client{bus.address()}; std::vector registrations; PowerArg power_supply_args[2]{ { repowerd::PowerSupply::battery, "battery" }, { repowerd::PowerSupply::line_power, "line-power" }}; std::chrono::milliseconds const timeout{30000}; int32_t const timeout_sec = std::chrono::duration_cast(timeout).count(); }; } TEST_F(ARepowerdSettingsService, replies_to_introspection_request) { auto reply = client.request_introspection(); EXPECT_THAT(reply.get(), StrNe("")); } TEST_F(ARepowerdSettingsService, forwards_set_inactivity_behavior_request_with_supported_actions) { PowerArg power_action_args[] = { { repowerd::PowerAction::display_off, "display-off" }, { repowerd::PowerAction::suspend, "suspend" }}; for (auto const& action_arg : power_action_args) { for (auto const& supply_arg : power_supply_args) { EXPECT_CALL(mock_handlers, set_inactivity_behavior( action_arg.value, supply_arg.value, timeout, _)); client.request_set_inactivity_behavior( action_arg.str, supply_arg.str, timeout_sec); Mock::VerifyAndClearExpectations(&mock_handlers); } } } TEST_F(ARepowerdSettingsService, forwards_set_inactivity_behavior_request_with_infinite_timeout_for_non_positive_request_timeout) { for (auto const request_timeout_sec : {-1, 0}) { EXPECT_CALL(mock_handlers, set_inactivity_behavior( repowerd::PowerAction::display_off, repowerd::PowerSupply::battery, repowerd::infinite_timeout, _)); client.request_set_inactivity_behavior( "display-off", "battery", request_timeout_sec); Mock::VerifyAndClearExpectations(&mock_handlers); } } TEST_F(ARepowerdSettingsService, does_not_forward_set_inactivity_behavior_request_with_unsupported_actions) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "invalid" }, { repowerd::PowerAction::none, "none" }, { repowerd::PowerAction::power_off, "power-off" }}; for (auto const& action_arg : power_action_args) { for (auto const& supply_arg : power_supply_args) { EXPECT_CALL(mock_handlers, set_inactivity_behavior(_, _, _, _)).Times(0); try { client.request_set_inactivity_behavior( action_arg.str, supply_arg.str, timeout_sec).get(); } catch (...) { } Mock::VerifyAndClearExpectations(&mock_handlers); } } } TEST_F(ARepowerdSettingsService, logs_set_inactivity_behavior_request) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "invalid" }, { repowerd::PowerAction::none, "none" }, { repowerd::PowerAction::display_off, "display-off" }, { repowerd::PowerAction::suspend, "suspend" }, { repowerd::PowerAction::power_off, "power-off" }}; for (auto const& action_arg : power_action_args) { for (auto const& supply_arg : power_supply_args) { try { client.request_set_inactivity_behavior( action_arg.str, supply_arg.str, timeout_sec).get(); } catch (...) { } EXPECT_TRUE( fake_log.contains_line( {"SetInactivityBehavior", action_arg.str, supply_arg.str, std::to_string(timeout_sec)})); } } } TEST_F(ARepowerdSettingsService, forwards_set_lid_behavior_request_with_supported_actions) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "none" }, { repowerd::PowerAction::suspend, "suspend" }}; for (auto const& action_arg : power_action_args) { for (auto const& supply_arg : power_supply_args) { EXPECT_CALL(mock_handlers, set_lid_behavior(action_arg.value, supply_arg.value, _)); client.request_set_lid_behavior(action_arg.str, supply_arg.str); Mock::VerifyAndClearExpectations(&mock_handlers); } } } TEST_F(ARepowerdSettingsService, does_not_forward_set_lid_behavior_request_with_unsupported_actions) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "invalid" }, { repowerd::PowerAction::none, "display-off" }, { repowerd::PowerAction::power_off, "power-off" }}; for (auto const& action_arg : power_action_args) { for (auto const& supply_arg : power_supply_args) { EXPECT_CALL(mock_handlers, set_lid_behavior(_, _, _)).Times(0); try { client.request_set_lid_behavior(action_arg.str, supply_arg.str).get(); } catch (...) { } Mock::VerifyAndClearExpectations(&mock_handlers); } } } TEST_F(ARepowerdSettingsService, logs_set_lid_behavior_request) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "invalid" }, { repowerd::PowerAction::none, "none" }, { repowerd::PowerAction::display_off, "display-off" }, { repowerd::PowerAction::suspend, "suspend" }, { repowerd::PowerAction::power_off, "power-off" }}; for (auto const& action_arg : power_action_args) { for (auto const& supply_arg : power_supply_args) { try { client.request_set_lid_behavior(action_arg.str, supply_arg.str).get(); } catch (...) { } EXPECT_TRUE( fake_log.contains_line( {"SetLidBehavior", action_arg.str, supply_arg.str})); } } } TEST_F(ARepowerdSettingsService, forwards_set_critical_power_behavior_request_with_supported_actions) { PowerArg power_action_args[] = { { repowerd::PowerAction::suspend, "suspend" }, { repowerd::PowerAction::power_off, "power-off" }}; for (auto const& action_arg : power_action_args) { EXPECT_CALL(mock_handlers, set_critical_power_behavior(action_arg.value, _)); client.request_set_critical_power_behavior(action_arg.str); Mock::VerifyAndClearExpectations(&mock_handlers); } } TEST_F(ARepowerdSettingsService, does_not_forward_set_critical_power_behavior_request_with_unsupported_actions) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "invalid" }, { repowerd::PowerAction::none, "none" }, { repowerd::PowerAction::display_off, "display-off" }}; for (auto const& action_arg : power_action_args) { EXPECT_CALL(mock_handlers, set_critical_power_behavior(_, _)).Times(0); try { client.request_set_critical_power_behavior(action_arg.str).get(); } catch (...) { } Mock::VerifyAndClearExpectations(&mock_handlers); } } TEST_F(ARepowerdSettingsService, logs_set_critical_power_behavior_request) { PowerArg power_action_args[] = { { repowerd::PowerAction::none, "invalid" }, { repowerd::PowerAction::none, "none" }, { repowerd::PowerAction::display_off, "display-off" }, { repowerd::PowerAction::suspend, "suspend" }, { repowerd::PowerAction::power_off, "power-off" }}; for (auto const& action_arg : power_action_args) { try { client.request_set_critical_power_behavior(action_arg.str).get(); } catch (...) { } EXPECT_TRUE( fake_log.contains_line({"SetCriticalPowerBehavior", action_arg.str})); } } repowerd-2023.07/tests/adapter-tests/test_sysfs_backlight.cpp000066400000000000000000000155321446034100200243620ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/sysfs_backlight.h" #include "src/adapters/path.h" #include "fake_filesystem.h" #include "fake_log.h" #include "fake_shared.h" #include #include #include #include namespace rt = repowerd::test; using namespace testing; namespace { class FakeSysfsBacklight { public: FakeSysfsBacklight( rt::FakeFilesystem& fake_fs, std::string const& type, int max_brightness) : path{repowerd::Path{"/sys/class/backlight"}/type} { fake_fs.add_file_with_contents(path/"type" , type); brightness_contents = fake_fs.add_file_with_live_contents( path/"brightness"); fake_fs.add_file_with_contents( path/"max_brightness", std::to_string(max_brightness)); brightness_contents->push_back("0"); } repowerd::Path const path; std::shared_ptr> brightness_contents; }; class FakeSysfsLedBacklight { public: FakeSysfsLedBacklight(rt::FakeFilesystem& fake_fs, int max_brightness) { brightness_contents = fake_fs.add_file_with_live_contents( "/sys/class/leds/lcd-backlight/brightness"); fake_fs.add_file_with_contents( "/sys/class/leds/lcd-backlight/max_brightness", std::to_string(max_brightness)); brightness_contents->push_back("0"); } std::shared_ptr> brightness_contents; }; struct ASysfsBacklight : Test { void set_up_sysfs_backlight() { sysfs_backlight = std::make_unique(fake_fs, "firmware", max_brightness); } std::unique_ptr set_up_sysfs_backlight_with_type(std::string const& type) { return std::make_unique(fake_fs, type, max_brightness); } void set_up_sysfs_led_backlight() { sysfs_led_backlight = std::make_unique(fake_fs, max_brightness); } std::unique_ptr create_sysfs_backlight() { return std::make_unique( rt::fake_shared(fake_log), rt::fake_shared(fake_fs)); } void expect_brightness_value(int brightness) { ASSERT_THAT(sysfs_backlight, NotNull()); EXPECT_THAT(sysfs_backlight->brightness_contents->back(), StrEq(std::to_string(brightness))); } rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeFilesystem fake_fs; int const max_brightness = 255; std::unique_ptr sysfs_backlight; std::unique_ptr sysfs_led_backlight; }; } TEST_F(ASysfsBacklight, fails_if_no_backlight_present) { EXPECT_THROW({ create_sysfs_backlight(); }, std::runtime_error); } TEST_F(ASysfsBacklight, uses_sysfs_backlight_if_present) { set_up_sysfs_backlight(); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.5); EXPECT_THAT(sysfs_backlight->brightness_contents->size(), Gt(1)); } TEST_F(ASysfsBacklight, uses_sysfs_led_backlight_if_present) { set_up_sysfs_led_backlight(); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.5); EXPECT_THAT(sysfs_led_backlight->brightness_contents->size(), Gt(1)); } TEST_F(ASysfsBacklight, prefers_sysfs_backlight_over_led_backlight_if_both_present) { set_up_sysfs_backlight(); set_up_sysfs_led_backlight(); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.5); EXPECT_THAT(sysfs_backlight->brightness_contents->size(), Gt(1)); EXPECT_THAT(sysfs_led_backlight->brightness_contents->size(), Eq(1)); } TEST_F(ASysfsBacklight, writes_brightness_value_based_on_max_brightness) { set_up_sysfs_backlight(); auto const normalized_brightness = 0.7; auto const backlight = create_sysfs_backlight(); backlight->set_brightness(normalized_brightness); expect_brightness_value(round(max_brightness * normalized_brightness)); } TEST_F(ASysfsBacklight, writes_zero_brightness_value_for_zero_brightness) { set_up_sysfs_backlight(); auto const normalized_brightness = 0.0; auto const backlight = create_sysfs_backlight(); backlight->set_brightness(normalized_brightness); expect_brightness_value(0); } TEST_F(ASysfsBacklight, gets_last_set_brightness) { set_up_sysfs_backlight(); auto const normalized_brightness = 0.7123; auto const backlight = create_sysfs_backlight(); backlight->set_brightness(normalized_brightness); EXPECT_THAT(backlight->get_brightness(), Eq(normalized_brightness)); } TEST_F(ASysfsBacklight, gets_real_brightness_if_brightness_changed_externally) { set_up_sysfs_backlight(); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.7); sysfs_backlight->brightness_contents->push_back("102"); EXPECT_THAT(backlight->get_brightness(), Eq(102.0/max_brightness)); } TEST_F(ASysfsBacklight, logs_used_sysfs_backlight_dir) { set_up_sysfs_backlight(); auto const backlight = create_sysfs_backlight(); EXPECT_TRUE(fake_log.contains_line({sysfs_backlight->path})); } TEST_F(ASysfsBacklight, prefers_firmware_backlight_over_all_others) { auto const firmware = set_up_sysfs_backlight_with_type("firmware"); auto const platform = set_up_sysfs_backlight_with_type("platform"); auto const raw = set_up_sysfs_backlight_with_type("raw"); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.5); EXPECT_THAT(firmware->brightness_contents->size(), Gt(1)); } TEST_F(ASysfsBacklight, prefers_platform_backlight_over_raw) { auto const platform = set_up_sysfs_backlight_with_type("platform"); auto const raw = set_up_sysfs_backlight_with_type("raw"); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.5); EXPECT_THAT(platform->brightness_contents->size(), Gt(1)); } TEST_F(ASysfsBacklight, uses_raw_backlight_if_no_other_choice) { auto const raw = set_up_sysfs_backlight_with_type("raw"); auto const backlight = create_sysfs_backlight(); backlight->set_brightness(0.5); EXPECT_THAT(raw->brightness_contents->size(), Gt(1)); } repowerd-2023.07/tests/adapter-tests/test_timerfd_wakeup_service.cpp000066400000000000000000000144131446034100200257260ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/timerfd_wakeup_service.h" #include "fake_log.h" #include "fake_shared.h" #include #include #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { bool about_equal(std::chrono::system_clock::time_point expected, std::chrono::system_clock::time_point actual) { return actual >= expected && (actual - expected) <= 10ms; } struct ATimerfdWakeupService : Test { ATimerfdWakeupService() { handler_registration = wakeup_service.register_wakeup_handler( [this] (std::string const& cookie) { wakeup_handler(cookie); }); } std::chrono::system_clock::time_point system_now() { return std::chrono::system_clock::now(); } void wakeup_handler(std::string const& cookie) { std::unique_lock lock{wakeup_mutex}; wakeup_time_points.push_back(system_now()); wakeup_cookies.push_back(cookie); wakeup_cv.notify_all(); } void wait_for_wakeups( std::vector const& cookies, std::vector const& time_points) { std::unique_lock lock{wakeup_mutex}; auto const result = wakeup_cv.wait_for( lock, 3s, [&] { return cookies == wakeup_cookies && time_points.size() == wakeup_time_points.size(); }); if (!result) throw std::runtime_error("Timeout waiting for wakeups"); for (auto i = 0u; i < time_points.size(); ++i) { if (!about_equal(time_points[i], wakeup_time_points[i])) { throw std::runtime_error( "Time point " + std::to_string(i) + " mismatch: " + "expected=" + std::to_string(time_points[i].time_since_epoch().count()) + " actual=" + std::to_string(wakeup_time_points[i].time_since_epoch().count())); } } } rt::FakeLog fake_log{repowerd::LogLevel::Debug}; repowerd::TimerfdWakeupService wakeup_service{rt::fake_shared(fake_log),}; std::mutex wakeup_mutex; std::condition_variable wakeup_cv; std::vector wakeup_cookies; std::vector wakeup_time_points; // Registration needs to be last, so that we unregister the wakeup handler // before destroying the test, to avoid accessing test variables in the // handler while the test is being destroyed. repowerd::HandlerRegistration handler_registration; }; } TEST_F(ATimerfdWakeupService, returns_different_cookies) { auto const tp1 = system_now() + 100ms; auto const tp2 = system_now() + 200ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); EXPECT_THAT(cookie1, StrNe("")); EXPECT_THAT(cookie2, StrNe("")); EXPECT_THAT(cookie1, StrNe(cookie2)); } TEST_F(ATimerfdWakeupService, schedules_wakeup) { auto const tp = system_now() + 100ms; auto cookie = wakeup_service.schedule_wakeup_at(tp); wait_for_wakeups({cookie}, {tp}); } TEST_F(ATimerfdWakeupService, cancels_wakeup) { auto const tp = system_now() + 50ms; auto const cookie = wakeup_service.schedule_wakeup_at(tp); wakeup_service.cancel_wakeup(cookie); std::this_thread::sleep_for(100ms); wait_for_wakeups({}, {}); } TEST_F(ATimerfdWakeupService, schedules_multiple_wakeups) { auto const tp1 = system_now() + 50ms; auto const tp2 = system_now() + 100ms; auto const tp3 = system_now() + 150ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); auto const cookie3 = wakeup_service.schedule_wakeup_at(tp3); wait_for_wakeups({cookie1, cookie2, cookie3}, {tp1, tp2, tp3}); } TEST_F(ATimerfdWakeupService, cancels_one_of_many_wakeups) { auto const tp1 = system_now() + 50ms; auto const tp2 = system_now() + 100ms; auto const tp3 = system_now() + 150ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); auto const cookie3 = wakeup_service.schedule_wakeup_at(tp3); wakeup_service.cancel_wakeup(cookie2); wait_for_wakeups({cookie1, cookie3}, {tp1, tp3}); } TEST_F(ATimerfdWakeupService, schedules_and_cancels_multiple_wakeups_with_same_time) { auto const tp1 = system_now() + 50ms; auto const tp2 = system_now() + 50ms; auto const tp3 = system_now() + 50ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); auto const cookie2 = wakeup_service.schedule_wakeup_at(tp2); auto const cookie3 = wakeup_service.schedule_wakeup_at(tp3); wakeup_service.cancel_wakeup(cookie2); wait_for_wakeups({cookie1, cookie3}, {tp1, tp3}); } TEST_F(ATimerfdWakeupService, does_not_leak_memory_when_triggering) { auto const tp1 = system_now() + 50ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); wait_for_wakeups({cookie1}, {tp1}); EXPECT_THAT(wakeup_service.num_stored_elements(), Eq(0)); } TEST_F(ATimerfdWakeupService, does_not_leak_memory_when_cancelling) { auto const tp1 = system_now() + 50ms; auto const cookie1 = wakeup_service.schedule_wakeup_at(tp1); wakeup_service.cancel_wakeup(cookie1); EXPECT_THAT(wakeup_service.num_stored_elements(), Eq(0)); } repowerd-2023.07/tests/adapter-tests/test_ubuntu_light_sensor.cpp000066400000000000000000000047211446034100200253030ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/ubuntu_light_sensor.h" #include "temporary_environment_value.h" #include "temporary_file.h" #include "test_in_separate_process.h" #include "wait_condition.h" #include #include #include #include #include namespace rt = repowerd::test; using namespace testing; namespace { struct AUbuntuLightSensor : testing::Test { void set_up_sensor(std::string const& script) { rt::TemporaryFile command_file; rt::TemporaryEnvironmentValue backend{"UBUNTU_PLATFORM_API_BACKEND", "test"}; rt::TemporaryEnvironmentValue test_file{"UBUNTU_PLATFORM_API_SENSOR_TEST", command_file.name().c_str()}; command_file.write(script); sensor = std::make_unique(); registration = sensor->register_light_handler( [this](double light) { mock_handlers.light_handler(light); }); } struct MockHandlers { MOCK_METHOD1(light_handler, void(double)); }; NiceMock mock_handlers; std::unique_ptr sensor; repowerd::HandlerRegistration registration; std::chrono::seconds const default_timeout{3}; }; } TEST_F(AUbuntuLightSensor, reports_light_events) { TEST_IN_SEPARATE_PROCESS({ rt::WaitCondition handler_called; InSequence seq; EXPECT_CALL(mock_handlers, light_handler(10)); EXPECT_CALL(mock_handlers, light_handler(30)) .WillOnce(WakeUp(&handler_called)); set_up_sensor( "create light 0 100 1\n" "500 light 10\n" "50 light 30\n"); sensor->enable_light_events(); handler_called.wait_for(default_timeout); EXPECT_TRUE(handler_called.woken()); }); } repowerd-2023.07/tests/adapter-tests/test_ubuntu_proximity_sensor.cpp000066400000000000000000000167161446034100200262470ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/ubuntu_proximity_sensor.h" #include "src/adapters/device_quirks.h" #include "fake_device_quirks.h" #include "fake_log.h" #include "fake_shared.h" #include "temporary_environment_value.h" #include "temporary_file.h" #include "test_in_separate_process.h" #include "wait_condition.h" #include #include #include namespace rt = repowerd::test; using namespace testing; namespace { struct AUbuntuProximitySensor : testing::Test { void set_up_sensor(std::string const& script) { rt::TemporaryFile command_file; rt::TemporaryEnvironmentValue backend{"UBUNTU_PLATFORM_API_BACKEND", "test"}; rt::TemporaryEnvironmentValue test_file{"UBUNTU_PLATFORM_API_SENSOR_TEST", command_file.name().c_str()}; command_file.write(script); sensor = std::make_unique( rt::fake_shared(fake_log), fake_device_quirks); registration = sensor->register_proximity_handler( [this](repowerd::ProximityState state) { mock_handlers.proximity_handler(state); }); } struct MockHandlers { MOCK_METHOD1(proximity_handler, void(repowerd::ProximityState)); }; NiceMock mock_handlers; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeDeviceQuirks fake_device_quirks; std::unique_ptr sensor; repowerd::HandlerRegistration registration; std::chrono::seconds const default_timeout{3}; }; } TEST_F(AUbuntuProximitySensor, reports_far_event) { TEST_IN_SEPARATE_PROCESS({ rt::WaitCondition handler_called; EXPECT_CALL(mock_handlers, proximity_handler(repowerd::ProximityState::far)) .WillOnce(WakeUp(&handler_called)); set_up_sensor( "create proximity\n" "500 proximity far\n"); sensor->enable_proximity_events(); handler_called.wait_for(default_timeout); EXPECT_TRUE(handler_called.woken()); EXPECT_TRUE(fake_log.contains_line({"proximity_event", "far"})); }); } TEST_F(AUbuntuProximitySensor, reports_near_event) { TEST_IN_SEPARATE_PROCESS({ rt::WaitCondition handler_called; EXPECT_CALL(mock_handlers, proximity_handler(repowerd::ProximityState::near)) .WillOnce(WakeUp(&handler_called)); set_up_sensor( "create proximity\n" "500 proximity near\n"); sensor->enable_proximity_events(); handler_called.wait_for(default_timeout); EXPECT_TRUE(handler_called.woken()); EXPECT_TRUE(fake_log.contains_line({"proximity_event", "near"})); }); } TEST_F(AUbuntuProximitySensor, reports_synthetic_event_far_if_no_initial_event_arrives) { TEST_IN_SEPARATE_PROCESS({ rt::WaitCondition handler_called; EXPECT_CALL(mock_handlers, proximity_handler(repowerd::ProximityState::far)) .WillOnce(WakeUp(&handler_called)); set_up_sensor( "create proximity\n"); sensor->enable_proximity_events(); handler_called.wait_for(default_timeout); EXPECT_TRUE(handler_called.woken()); EXPECT_TRUE(fake_log.contains_line({"schedule", "synthetic", "far"})); EXPECT_TRUE(fake_log.contains_line({"emitting", "synthetic", "far"})); EXPECT_TRUE(fake_log.contains_line({"proximity_event", "far"})); }); } TEST_F(AUbuntuProximitySensor, reports_synthetic_event_near_if_no_initial_event_arrives) { TEST_IN_SEPARATE_PROCESS({ fake_device_quirks.set_synthetic_initial_event_type_near(); rt::WaitCondition handler_called; EXPECT_CALL(mock_handlers, proximity_handler(repowerd::ProximityState::near)) .WillOnce(WakeUp(&handler_called)); set_up_sensor( "create proximity\n"); sensor->enable_proximity_events(); handler_called.wait_for(default_timeout); EXPECT_TRUE(handler_called.woken()); EXPECT_TRUE(fake_log.contains_line({"schedule", "synthetic", "near"})); EXPECT_TRUE(fake_log.contains_line({"emitting", "synthetic", "near"})); EXPECT_TRUE(fake_log.contains_line({"proximity_event", "near"})); }); } TEST_F(AUbuntuProximitySensor, reports_current_state) { TEST_IN_SEPARATE_PROCESS({ set_up_sensor( "create proximity\n" "500 proximity near\n"); sensor->enable_proximity_events(); std::this_thread::sleep_for(std::chrono::milliseconds{750}); EXPECT_THAT(sensor->proximity_state(), Eq(repowerd::ProximityState::near)); EXPECT_TRUE(fake_log.contains_line({"proximity_state", "near"})); }); } TEST_F(AUbuntuProximitySensor, waits_for_first_event_to_report_current_state) { TEST_IN_SEPARATE_PROCESS({ set_up_sensor( "create proximity\n" "500 proximity near\n"); EXPECT_THAT(sensor->proximity_state(), Eq(repowerd::ProximityState::near)); EXPECT_TRUE(fake_log.contains_line({"proximity_state", "near"})); }); } TEST_F(AUbuntuProximitySensor, reports_current_synthetic_state_far_if_no_event_arrives_soon) { TEST_IN_SEPARATE_PROCESS({ set_up_sensor( "create proximity\n"); EXPECT_THAT(sensor->proximity_state(), Eq(repowerd::ProximityState::far)); EXPECT_TRUE(fake_log.contains_line({"proximity_state", "far"})); }); } TEST_F(AUbuntuProximitySensor, reports_current_synthetic_state_near_if_no_event_arrives_soon) { TEST_IN_SEPARATE_PROCESS({ fake_device_quirks.set_synthetic_initial_event_type_near(); set_up_sensor( "create proximity\n"); EXPECT_THAT(sensor->proximity_state(), Eq(repowerd::ProximityState::near)); EXPECT_TRUE(fake_log.contains_line({"proximity_state", "near"})); }); } TEST_F(AUbuntuProximitySensor, logs_enable_and_disable_proximity_events) { TEST_IN_SEPARATE_PROCESS({ set_up_sensor( "create proximity\n"); sensor->enable_proximity_events(); EXPECT_TRUE(fake_log.contains_line({"enable", "proximity_events"})); EXPECT_FALSE(fake_log.contains_line({"disable", "proximity_events"})); sensor->disable_proximity_events(); EXPECT_TRUE(fake_log.contains_line({"disable", "proximity_events"})); }); } TEST_F(AUbuntuProximitySensor, ignores_stray_proximity_events_when_disabled) { TEST_IN_SEPARATE_PROCESS({ EXPECT_CALL(mock_handlers, proximity_handler(_)).Times(0); set_up_sensor( "create proximity\n"); sensor->emit_proximity_event(repowerd::ProximityState::near); EXPECT_TRUE(fake_log.contains_line({"handle_proximity_event", "near", "ignoring"})); EXPECT_THAT(sensor->proximity_state(), Eq(repowerd::ProximityState::far)); std::this_thread::sleep_for(std::chrono::milliseconds{1100}); }); } repowerd-2023.07/tests/adapter-tests/test_unique_random_pool.cpp000066400000000000000000000051201446034100200250720ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/adapters/unique_random_pool.h" #include #include #include using namespace testing; namespace { struct AUniqueRandomPool : Test { template std::set generate( repowerd::UniqueRandomPool& pool, size_t n) { std::set generated; for (size_t i = 0; i < n; ++i) generated.insert(pool.generate()); return generated; } repowerd::UniqueRandomPool unique_random_pool; size_t const nvalues = std::numeric_limits::max() + 1; }; } TEST_F(AUniqueRandomPool, generates_different_values) { auto const generated = generate(unique_random_pool, nvalues); EXPECT_THAT(generated.size(), Eq(nvalues)); } TEST_F(AUniqueRandomPool, generates_value_again_if_removed) { repowerd::UniqueRandomPool unique_random_pool; auto const generated_partial = generate(unique_random_pool, 100); EXPECT_THAT(generated_partial.size(), Eq(100)); for (auto g : generated_partial) unique_random_pool.remove(g); auto const generated_full = generate(unique_random_pool, nvalues); EXPECT_THAT(generated_full.size(), Eq(nvalues)); } TEST_F(AUniqueRandomPool, generates_values_from_specified_min) { size_t const min_value = 200; repowerd::UniqueRandomPool unique_random_pool_with_min{min_value}; auto const nvalues_with_min = nvalues - min_value; auto const generated = generate(unique_random_pool_with_min, nvalues_with_min); for (auto g : generated) EXPECT_THAT(g, Ge(min_value)); EXPECT_THAT(generated.size(), Eq(nvalues_with_min)); } TEST_F(AUniqueRandomPool, reports_size) { generate(unique_random_pool, 100); EXPECT_THAT(unique_random_pool.size(), 100); } TEST_F(AUniqueRandomPool, throws_exception_if_exhausted) { EXPECT_THROW({ generate(unique_random_pool, nvalues + 1); }, std::runtime_error); } repowerd-2023.07/tests/adapter-tests/test_unity_screen_service.cpp000066400000000000000000000615431446034100200254350ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "fake_brightness_notification.h" #include "fake_device_config.h" #include "fake_double_tap_to_wake.h" #include "fake_filesystem.h" #include "fake_log.h" #include "fake_wakeup_service.h" #include "unity_screen_dbus_client.h" #include "src/adapters/dbus_connection_handle.h" #include "src/adapters/dbus_message_handle.h" #include "src/adapters/temporary_suspend_inhibition.h" #include "src/adapters/unity_screen_power_state_change_reason.h" #include "src/adapters/unity_screen_service.h" #include "src/core/infinite_timeout.h" #include "fake_shared.h" #include "wait_condition.h" #include #include #include using namespace testing; namespace rt = repowerd::test; namespace { struct NullTemporarySuspendInhibition : repowerd::TemporarySuspendInhibition { void inhibit_suspend_for(std::chrono::milliseconds, std::string const&) {} }; struct AUnityScreenService : testing::Test { AUnityScreenService() { registrations.push_back( service.register_disable_inactivity_timeout_handler( [this](auto id, auto pid){ mock_handlers.disable_inactivity_timeout(id, pid); })); registrations.push_back( service.register_enable_inactivity_timeout_handler( [this](auto id, auto pid) { mock_handlers.enable_inactivity_timeout(id, pid); })); registrations.push_back( service.register_set_inactivity_timeout_handler( [this] (std::chrono::milliseconds ms, auto pid) { mock_handlers.set_inactivity_timeout(ms, pid); })); registrations.push_back( service.register_disable_autobrightness_handler( [this] (auto pid) { mock_handlers.disable_autobrightness(pid); })); registrations.push_back( service.register_enable_autobrightness_handler( [this] (auto pid) { mock_handlers.enable_autobrightness(pid); })); registrations.push_back( service.register_set_normal_brightness_value_handler( [this] (double v, auto pid) { mock_handlers.set_normal_brightness_value(v, pid); })); registrations.push_back( service.register_notification_handler( [this](auto id, auto pid) { mock_handlers.notification(id, pid); })); registrations.push_back( service.register_notification_done_handler( [this](auto id, auto pid) { mock_handlers.notification_done(id, pid); })); service.start_processing(); } struct MockHandlers { MOCK_METHOD2(disable_inactivity_timeout, void(std::string const&, pid_t)); MOCK_METHOD2(enable_inactivity_timeout, void(std::string const&, pid_t)); MOCK_METHOD2(set_inactivity_timeout, void(std::chrono::milliseconds, pid_t)); MOCK_METHOD1(disable_autobrightness, void(pid_t)); MOCK_METHOD1(enable_autobrightness, void(pid_t)); MOCK_METHOD2(set_normal_brightness_value, void(double, pid_t)); MOCK_METHOD2(notification, void(std::string const&, pid_t)); MOCK_METHOD2(notification_done, void(std::string const&, pid_t)); }; testing::NiceMock mock_handlers; static int constexpr notification_reason{4}; static int constexpr snap_decision_reason{5}; std::chrono::seconds const default_timeout{3}; rt::DBusBus bus; rt::FakeBrightnessNotification fake_brightness_notification; rt::FakeDeviceConfig fake_device_config; rt::FakeFilesystem fake_filesystem; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; rt::FakeWakeupService fake_wakeup_service; rt::FakeDoubleTapToWake fake_double_tap_to_wake{ rt::fake_shared(fake_log), rt::fake_shared(fake_filesystem)}; NullTemporarySuspendInhibition null_temporary_suspend_inhibition; repowerd::UnityScreenService service{ rt::fake_shared(fake_wakeup_service), rt::fake_shared(fake_brightness_notification), rt::fake_shared(fake_log), rt::fake_shared(null_temporary_suspend_inhibition), rt::fake_shared(fake_double_tap_to_wake), fake_device_config, bus.address()}; rt::UnityScreenDBusClient client{bus.address()}; std::vector registrations; }; ACTION_P(AppendArg0To, dst) { return dst->push_back(arg0); } } TEST_F(AUnityScreenService, replies_to_introspection_request) { auto reply = client.request_introspection(); EXPECT_THAT(reply.get(), StrNe("")); } TEST_F(AUnityScreenService, forwards_keep_display_on_request) { EXPECT_CALL(mock_handlers, disable_inactivity_timeout(_, _)); client.request_keep_display_on(); } TEST_F(AUnityScreenService, replies_with_different_ids_to_keep_display_on_requests) { auto reply1 = client.request_keep_display_on(); auto reply2 = client.request_keep_display_on(); auto const id1 = reply1.get(); auto const id2 = reply2.get(); EXPECT_THAT(id1, Ne(id2)); } TEST_F(AUnityScreenService, disables_and_enables_inactivity_timeout_for_keep_display_on_request) { std::string id_disable; std::string id_enable; InSequence s; EXPECT_CALL(mock_handlers, disable_inactivity_timeout(_, _)) .WillOnce(SaveArg<0>(&id_disable)); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .WillOnce(SaveArg<0>(&id_enable)); auto reply1 = client.request_keep_display_on(); client.request_remove_display_on_request(reply1.get()); EXPECT_THAT(id_enable, Eq(id_disable)); } TEST_F(AUnityScreenService, disables_and_enables_inactivity_timeout_for_multiple_keep_display_on_requests) { std::vector id_disable; std::vector id_enable; EXPECT_CALL(mock_handlers, disable_inactivity_timeout(_, _)) .Times(3).WillRepeatedly(AppendArg0To(&id_disable)); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .Times(2).WillRepeatedly(AppendArg0To(&id_enable)); auto reply1 = client.request_keep_display_on(); auto reply2 = client.request_keep_display_on(); auto reply3 = client.request_keep_display_on(); client.request_remove_display_on_request(reply1.get()); client.request_remove_display_on_request(reply2.get()); auto id3 = reply3.get(); Mock::VerifyAndClearExpectations(&mock_handlers); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .WillOnce(AppendArg0To(&id_enable)); client.request_remove_display_on_request(id3); EXPECT_THAT(id_enable, ContainerEq(id_disable)); } TEST_F(AUnityScreenService, removes_all_client_inactivity_disablements_when_client_disconnects) { std::vector id_disable; std::vector id_enable; rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, disable_inactivity_timeout(_, _)) .Times(3).WillRepeatedly(AppendArg0To(&id_disable)); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .WillOnce(AppendArg0To(&id_enable)) .WillOnce(AppendArg0To(&id_enable)) .WillOnce(DoAll(AppendArg0To(&id_enable), WakeUp(&request_processed))); client.request_keep_display_on(); client.request_keep_display_on(); client.request_keep_display_on(); client.disconnect(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_THAT(id_enable, UnorderedElementsAreArray(id_disable)); } TEST_F(AUnityScreenService, removes_client_inactivity_disablements_when_all_clients_disconnect_or_remove_requests) { std::vector id_disable; std::vector id_enable; rt::UnityScreenDBusClient other_client{bus.address()}; rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, disable_inactivity_timeout(_, _)) .Times(4).WillRepeatedly(AppendArg0To(&id_disable)); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .WillOnce(AppendArg0To(&id_enable)) .WillOnce(AppendArg0To(&id_enable)) .WillOnce(DoAll(AppendArg0To(&id_enable), WakeUp(&request_processed))); auto reply1 = client.request_keep_display_on(); auto reply2 = client.request_keep_display_on(); other_client.request_keep_display_on(); other_client.request_keep_display_on(); other_client.disconnect(); client.request_remove_display_on_request(reply1.get()); auto id2 = reply2.get(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); Mock::VerifyAndClearExpectations(&mock_handlers); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .WillOnce(AppendArg0To(&id_enable)); client.request_remove_display_on_request(id2); EXPECT_THAT(id_enable, UnorderedElementsAreArray(id_disable)); } TEST_F(AUnityScreenService, ignores_invalid_display_on_removal_request) { int32_t const invalid_id{-1}; EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)).Times(0); client.request_remove_display_on_request(invalid_id); client.disconnect(); // Allow some time for dbus calls to reach UnityScreenService std::this_thread::sleep_for(std::chrono::milliseconds(100)); } TEST_F(AUnityScreenService, ignores_disconnects_from_clients_without_display_on_request) { EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)).Times(0); client.disconnect(); // Allow some time for disconnect notification to reach UnityScreenService std::this_thread::sleep_for(std::chrono::milliseconds(100)); } TEST_F(AUnityScreenService, forwards_set_inactivity_timeouts_request) { int32_t const poweroff_timeout = 10; int32_t const dimmer_timeout = 5; EXPECT_CALL(mock_handlers, set_inactivity_timeout(std::chrono::milliseconds{1000 * poweroff_timeout}, _)); client.request_set_inactivity_timeouts(poweroff_timeout, dimmer_timeout); } TEST_F(AUnityScreenService, forwards_infinite_inactivity_timeouts_request) { int32_t const infinite_poweroff_timeout = 0; int32_t const dimmer_timeout = 5; EXPECT_CALL(mock_handlers, set_inactivity_timeout(repowerd::infinite_timeout, _)); client.request_set_inactivity_timeouts(infinite_poweroff_timeout, dimmer_timeout); } TEST_F(AUnityScreenService, ignores_negative_inactivity_timeouts_request) { int32_t const negative_poweroff_timeout = -1; int32_t const dimmer_timeout = 5; EXPECT_CALL(mock_handlers, set_inactivity_timeout(_, _)).Times(0); client.request_set_inactivity_timeouts(negative_poweroff_timeout, dimmer_timeout); // Allow some time for dbus calls to reach UnityScreenService std::this_thread::sleep_for(std::chrono::milliseconds(100)); } TEST_F(AUnityScreenService, forwards_user_auto_brightness_disable_request) { bool const disable = false; EXPECT_CALL(mock_handlers, disable_autobrightness(_)); client.request_user_auto_brightness_enable(disable); } TEST_F(AUnityScreenService, forwards_user_auto_brightness_enable_request) { bool const enable = true; EXPECT_CALL(mock_handlers, enable_autobrightness(_)); client.request_user_auto_brightness_enable(enable); } TEST_F(AUnityScreenService, forwards_set_user_brightness_request) { int const brightness = 10; double const brightness_normalized = brightness / static_cast(fake_device_config.brightness_max_value); EXPECT_CALL(mock_handlers, set_normal_brightness_value(brightness_normalized, _)); client.request_set_user_brightness(brightness); } TEST_F(AUnityScreenService, forwards_set_screen_power_mode_notification_on_request) { EXPECT_CALL(mock_handlers, notification(_, _)); auto reply = client.request_set_screen_power_mode("on", notification_reason); EXPECT_THAT(reply.get(), Eq(true)); } TEST_F(AUnityScreenService, forwards_set_screen_power_mode_snap_decision_on_request_as_notification) { EXPECT_CALL(mock_handlers, notification(_, _)); auto reply = client.request_set_screen_power_mode("on", snap_decision_reason); EXPECT_THAT(reply.get(), Eq(true)); } TEST_F(AUnityScreenService, notifies_of_notification_done_for_all_notifications_and_snap_decisions) { std::vector notification_ids; std::vector notification_done_ids; EXPECT_CALL(mock_handlers, notification(_, _)) .Times(3).WillRepeatedly(AppendArg0To(¬ification_ids)); client.request_set_screen_power_mode("on", notification_reason); client.request_set_screen_power_mode("on", snap_decision_reason); client.request_set_screen_power_mode("on", notification_reason); Mock::VerifyAndClearExpectations(&mock_handlers); EXPECT_CALL(mock_handlers, notification(_, _)).Times(0); EXPECT_CALL(mock_handlers, notification_done(_, _)) .Times(3).WillRepeatedly(AppendArg0To(¬ification_done_ids)); client.request_set_screen_power_mode("off", notification_reason); client.request_set_screen_power_mode("off", notification_reason); client.request_set_screen_power_mode("off", snap_decision_reason); EXPECT_THAT(notification_done_ids, UnorderedElementsAreArray(notification_ids)); } TEST_F(AUnityScreenService, notifies_of_notification_done_when_single_client_disconnects) { std::vector notification_ids; std::vector notification_done_ids; rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, notification(_, _)) .Times(3).WillRepeatedly(AppendArg0To(¬ification_ids)); EXPECT_CALL(mock_handlers, notification_done(_, _)) .WillOnce(AppendArg0To(¬ification_done_ids)) .WillOnce(AppendArg0To(¬ification_done_ids)) .WillOnce(DoAll(AppendArg0To(¬ification_done_ids),WakeUp(&request_processed))); client.request_set_screen_power_mode("on", notification_reason); client.request_set_screen_power_mode("on", notification_reason); client.request_set_screen_power_mode("on", snap_decision_reason); client.disconnect(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_THAT(notification_done_ids, UnorderedElementsAreArray(notification_ids)); } TEST_F(AUnityScreenService, notifies_of_notification_done_for_all_clients_that_disconnect_or_remove_requests) { std::vector notification_ids; std::vector notification_done_ids; rt::UnityScreenDBusClient other_client{bus.address()}; EXPECT_CALL(mock_handlers, notification(_, _)) .Times(4).WillRepeatedly(AppendArg0To(¬ification_ids)); client.request_set_screen_power_mode("on", notification_reason); client.request_set_screen_power_mode("on", snap_decision_reason); other_client.request_set_screen_power_mode("on", notification_reason); other_client.request_set_screen_power_mode("on", snap_decision_reason); Mock::VerifyAndClearExpectations(&mock_handlers); rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, notification_done(_, _)) .WillOnce(AppendArg0To(¬ification_done_ids)) .WillOnce(AppendArg0To(¬ification_done_ids)) .WillOnce(AppendArg0To(¬ification_done_ids)) .WillOnce(DoAll(AppendArg0To(¬ification_done_ids), WakeUp(&request_processed))); other_client.disconnect(); client.request_set_screen_power_mode("off", notification_reason); client.request_set_screen_power_mode("off", snap_decision_reason); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUnityScreenService, ignores_notification_done_request_from_client_without_notifications) { EXPECT_CALL(mock_handlers, notification_done(_, _)).Times(0); client.request_set_screen_power_mode("off", notification_reason); } TEST_F(AUnityScreenService, ignores_disconnects_from_clients_without_notifications) { EXPECT_CALL(mock_handlers, notification_done(_, _)).Times(0); client.disconnect(); // Allow some time for disconnect notification to reach UnityScreenService std::this_thread::sleep_for(std::chrono::milliseconds(100)); } TEST_F(AUnityScreenService, returns_false_for_unsupported_set_screen_power_mode_request) { static int constexpr unknown_reason = 0; auto reply1 = client.request_set_screen_power_mode("on", unknown_reason); auto reply2 = client.request_set_screen_power_mode("off", unknown_reason); EXPECT_THAT(reply1.get(), Eq(false)); EXPECT_THAT(reply2.get(), Eq(false)); } TEST_F(AUnityScreenService, returns_error_reply_for_invalid_method) { auto reply = client.request_invalid_method(); auto reply_msg = reply.get(); EXPECT_THAT(g_dbus_message_get_message_type(reply_msg), Eq(G_DBUS_MESSAGE_TYPE_ERROR)); } TEST_F(AUnityScreenService, returns_error_reply_for_method_with_invalid_interface) { auto reply = client.request_method_with_invalid_interface(); auto reply_msg = reply.get(); EXPECT_THAT(g_dbus_message_get_message_type(reply_msg), Eq(G_DBUS_MESSAGE_TYPE_ERROR)); } TEST_F(AUnityScreenService, returns_error_reply_for_method_with_invalid_arguments) { auto reply = client.request_method_with_invalid_arguments(); auto reply_msg = reply.get(); EXPECT_THAT(g_dbus_message_get_message_type(reply_msg), Eq(G_DBUS_MESSAGE_TYPE_ERROR)); } TEST_F(AUnityScreenService, returns_error_reply_for_set_touch_visualization_enabled_request) { auto reply = client.request_set_touch_visualization_enabled(true); auto reply_msg = static_cast(&reply)->get(); EXPECT_THAT(g_dbus_message_get_message_type(reply_msg), Eq(G_DBUS_MESSAGE_TYPE_ERROR)); } TEST_F(AUnityScreenService, does_not_call_unregistered_handlers) { EXPECT_CALL(mock_handlers, disable_inactivity_timeout(_, _)).Times(0); EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)).Times(0); EXPECT_CALL(mock_handlers, set_inactivity_timeout(_, _)).Times(0); EXPECT_CALL(mock_handlers, disable_autobrightness(_)).Times(0); EXPECT_CALL(mock_handlers, enable_autobrightness(_)).Times(0); EXPECT_CALL(mock_handlers, set_normal_brightness_value(_, _)).Times(0); EXPECT_CALL(mock_handlers, notification(_, _)).Times(0); EXPECT_CALL(mock_handlers, notification_done(_, _)).Times(0); registrations.clear(); client.request_set_user_brightness(10); client.request_user_auto_brightness_enable(true); client.request_set_inactivity_timeouts(1, 1); client.request_set_screen_power_mode("on", notification_reason); auto reply = client.request_keep_display_on(); client.request_remove_display_on_request(reply.get()); } TEST_F(AUnityScreenService, emits_display_power_state_change_signal) { std::promise promise; auto const reg = client.register_display_power_state_change_handler( [&promise] (auto v) { promise.set_value(v); }); struct TestValues { repowerd::DisplayPowerChangeReason reason; repowerd::UnityScreenPowerStateChangeReason unity_screen_reason; }; std::vector const test_values = { {repowerd::DisplayPowerChangeReason::activity, repowerd::UnityScreenPowerStateChangeReason::inactivity}, {repowerd::DisplayPowerChangeReason::power_button, repowerd::UnityScreenPowerStateChangeReason::power_key}, {repowerd::DisplayPowerChangeReason::proximity, repowerd::UnityScreenPowerStateChangeReason::proximity}, {repowerd::DisplayPowerChangeReason::notification, repowerd::UnityScreenPowerStateChangeReason::notification}, {repowerd::DisplayPowerChangeReason::call_done, repowerd::UnityScreenPowerStateChangeReason::call_done}, {repowerd::DisplayPowerChangeReason::call, repowerd::UnityScreenPowerStateChangeReason::unknown}, }; for (auto const& v : test_values) { promise = {}; auto future = promise.get_future(); service.notify_display_power_on(v.reason); auto const params = future.get(); EXPECT_THAT(params.power_state, Eq(1)); EXPECT_THAT(params.reason, Eq(static_cast(v.unity_screen_reason))); } for (auto const& v : test_values) { promise = {}; auto future = promise.get_future(); service.notify_display_power_off(v.reason); auto const params = future.get(); EXPECT_THAT(params.power_state, Eq(0)); EXPECT_THAT(params.reason, Eq(static_cast(v.unity_screen_reason))); } } TEST_F(AUnityScreenService, logs_keep_display_on_request) { auto const id = client.request_keep_display_on().get(); EXPECT_TRUE( fake_log.contains_line( {"keepDisplayOn", client.unique_name(), std::to_string(id)})); } TEST_F(AUnityScreenService, logs_remove_display_on_request) { auto const id = client.request_keep_display_on().get(); client.request_remove_display_on_request(id).get(); EXPECT_TRUE( fake_log.contains_line({ "removeDisplayOnRequest", client.unique_name(), std::to_string(id)})); } TEST_F(AUnityScreenService, logs_user_auto_brightness_disable_request) { client.request_user_auto_brightness_enable(false).get(); EXPECT_TRUE(fake_log.contains_line({"userAutobrightnessEnable", "disable"})); } TEST_F(AUnityScreenService, logs_user_auto_brightness_enable_request) { client.request_user_auto_brightness_enable(true).get(); EXPECT_TRUE(fake_log.contains_line({"userAutobrightnessEnable", "enable"})); } TEST_F(AUnityScreenService, logs_set_user_brightness_request) { int const brightness = 30; client.request_set_user_brightness(brightness).get(); EXPECT_TRUE(fake_log.contains_line({"setUserBrightness", std::to_string(brightness)})); } TEST_F(AUnityScreenService, logs_set_inactivity_timeouts_request) { int32_t const poweroff_timeout = 10; int32_t const dimmer_timeout = 5; client.request_set_inactivity_timeouts(poweroff_timeout, dimmer_timeout).get(); EXPECT_TRUE( fake_log.contains_line({ "setInactivityTimeouts", std::to_string(poweroff_timeout), std::to_string(dimmer_timeout)})); } TEST_F(AUnityScreenService, logs_set_screen_power_mode_request) { client.request_set_screen_power_mode("on", notification_reason).get(); EXPECT_TRUE( fake_log.contains_line({ "setScreenPowerMode", client.unique_name(), "on", std::to_string(notification_reason)})); } TEST_F(AUnityScreenService, logs_emit_display_power_change_signal_for_on) { service.notify_display_power_on( repowerd::DisplayPowerChangeReason::proximity); EXPECT_TRUE( fake_log.contains_line({ "emit", "DisplayPowerStateChange", "1", std::to_string( static_cast( repowerd::UnityScreenPowerStateChangeReason::proximity))})); } TEST_F(AUnityScreenService, logs_emit_display_power_change_signal_for_off) { service.notify_display_power_off( repowerd::DisplayPowerChangeReason::power_button); EXPECT_TRUE( fake_log.contains_line({ "emit", "DisplayPowerStateChange", "0", std::to_string( static_cast( repowerd::UnityScreenPowerStateChangeReason::power_key))})); } TEST_F(AUnityScreenService, does_not_log_name_owner_changed_for_untracked_clients) { client.disconnect(); EXPECT_FALSE(fake_log.contains_line({"NameOwnerChanged"})); } TEST_F(AUnityScreenService, logs_name_owner_changed_for_tracked_keep_display_on_clients) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, enable_inactivity_timeout(_, _)) .WillOnce(WakeUp(&request_processed)); client.request_keep_display_on().get(); client.disconnect(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line({"NameOwnerChanged", client.unique_name()})); } TEST_F(AUnityScreenService, logs_name_owner_changed_for_tracked_notification_clients) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, notification_done(_, _)) .WillOnce(WakeUp(&request_processed)); client.request_set_screen_power_mode("on", notification_reason).get(); client.disconnect(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line({"NameOwnerChanged", client.unique_name()})); } repowerd-2023.07/tests/adapter-tests/test_upower_power_source_and_lid.cpp000066400000000000000000000444071446034100200267750ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "dbus_bus.h" #include "dbus_client.h" #include "fake_device_config.h" #include "fake_log.h" #include "fake_shared.h" #include "fake_upower.h" #include "spin_wait.h" #include "wait_condition.h" #include "src/adapters/upower_power_source_and_lid.h" #include "src/adapters/temporary_suspend_inhibition.h" #include #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct MockTemporarySuspendInhibition : repowerd::TemporarySuspendInhibition { MOCK_METHOD2(inhibit_suspend_for, void(std::chrono::milliseconds,std::string const&)); }; struct AUPowerPowerSourceAndLidBase : testing::Test { AUPowerPowerSourceAndLidBase() { registrations.push_back( upower_power_source_and_lid.register_power_source_change_handler( [this] { mock_handlers.power_source_change(); })); registrations.push_back( upower_power_source_and_lid.register_power_source_critical_handler( [this] { mock_handlers.power_source_critical(); })); registrations.push_back( upower_power_source_and_lid.register_lid_handler( [this] (repowerd::LidState lid_state) { mock_handlers.lid(lid_state); })); } void wait_for_tracked_batteries(std::unordered_set const& batteries) { auto const result = rt::spin_wait_for_condition_or_timeout( [this,&batteries] { return upower_power_source_and_lid.tracked_batteries() == batteries; }, default_timeout); if (!result) throw std::runtime_error("Timeout while waiting for tracked batteries"); } std::string device_path(int i) { return "/org/freedesktop/UPower/devices/" + std::to_string(i); } struct MockHandlers { MOCK_METHOD0(power_source_change, void()); MOCK_METHOD0(power_source_critical, void()); MOCK_METHOD1(lid, void(repowerd::LidState)); }; testing::NiceMock mock_handlers; rt::DBusBus bus; rt::FakeDeviceConfig fake_device_config; rt::FakeLog fake_log{repowerd::LogLevel::Debug}; NiceMock mock_temporary_suspend_inhibition; repowerd::UPowerPowerSourceAndLid upower_power_source_and_lid{ rt::fake_shared(fake_log), rt::fake_shared(mock_temporary_suspend_inhibition), fake_device_config, bus.address()}; rt::FakeUPower fake_upower{bus.address()}; std::vector registrations; // shutdown_battery_temperature is in celcius * 10 double const exploding_temperature = fake_device_config.shutdown_battery_temperature * 0.1; double const critical_percentage = 2.0; double const non_critical_percentage = 3.0; rt::FakeUPower::DeviceInfo const plugged_line_power = rt::FakeUPower::DeviceInfo::for_plugged_line_power(); rt::FakeUPower::DeviceInfo const unplugged_line_power = rt::FakeUPower::DeviceInfo::for_unplugged_line_power(); rt::FakeUPower::DeviceInfo const full_battery = rt::FakeUPower::DeviceInfo::for_battery(rt::FakeUPower::DeviceState::fully_charged); rt::FakeUPower::DeviceInfo const discharging_battery = rt::FakeUPower::DeviceInfo::for_battery(rt::FakeUPower::DeviceState::discharging); rt::FakeUPower::DeviceInfo const charging_battery = rt::FakeUPower::DeviceInfo::for_battery(rt::FakeUPower::DeviceState::charging); rt::FakeUPower::DeviceInfo const pending_charge_battery = rt::FakeUPower::DeviceInfo::for_battery(rt::FakeUPower::DeviceState::pending_charge); std::chrono::seconds const default_timeout{3}; std::string const display_device_path{ "/org/freedesktop/UPower/devices/DisplayDevice"}; }; struct AUPowerPowerSourceAndLid : AUPowerPowerSourceAndLidBase { AUPowerPowerSourceAndLid() { fake_upower.add_device(device_path(0), unplugged_line_power); fake_upower.add_device(device_path(1), full_battery); fake_upower.add_device(display_device_path, full_battery); upower_power_source_and_lid.start_processing(); } }; struct AUPowerPowerSourceAndLidWithAlmostEmptyBattery : AUPowerPowerSourceAndLidBase { AUPowerPowerSourceAndLidWithAlmostEmptyBattery() { auto almost_empty_battery = discharging_battery; almost_empty_battery.percentage = critical_percentage; fake_upower.add_device(device_path(0), unplugged_line_power); fake_upower.add_device(device_path(1), almost_empty_battery); fake_upower.add_device(display_device_path, almost_empty_battery); } }; } TEST_F(AUPowerPowerSourceAndLid, notifies_of_change_from_full_to_discharging) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_change()) .WillOnce(WakeUp(&request_processed)); fake_upower.change_device(display_device_path, discharging_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_change_from_discharging_to_full) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_change()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); fake_upower.change_device(display_device_path, discharging_battery); fake_upower.change_device(display_device_path, full_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_change_from_discharging_to_charging) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_change()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); fake_upower.change_device(display_device_path, discharging_battery); fake_upower.change_device(display_device_path, charging_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_change_from_discharging_to_pending_charge) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_change()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); fake_upower.change_device(display_device_path, discharging_battery); fake_upower.change_device(display_device_path, pending_charge_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_change_from_full_to_charging_and_vice_versa) { EXPECT_CALL(mock_handlers, power_source_change()).Times(0); fake_upower.change_device(display_device_path, charging_battery); fake_upower.change_device(display_device_path, full_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_change_in_display_device_type) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_change()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); fake_upower.change_device(display_device_path, plugged_line_power); fake_upower.change_device(display_device_path, charging_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_state_changes_for_non_display_devices) { EXPECT_CALL(mock_handlers, power_source_change()).Times(0); fake_upower.change_device(device_path(1), discharging_battery); fake_upower.change_device(device_path(0), plugged_line_power); fake_upower.change_device(device_path(1), charging_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_critical_state_for_low_battery_energy_when_unplugged) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(WakeUp(&request_processed)); auto almost_empty_battery = discharging_battery; almost_empty_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, almost_empty_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line({"critical", "energy", "2.0%"})); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_critical_state_for_low_battery_energy_when_plugged) { EXPECT_CALL(mock_handlers, power_source_critical()).Times(0); auto low_charging_battery = charging_battery; low_charging_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, low_charging_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_critical_state_for_low_battery_for_non_display_devices) { EXPECT_CALL(mock_handlers, power_source_critical()).Times(0); auto low_charging_battery = discharging_battery; low_charging_battery.percentage = critical_percentage; fake_upower.change_device(device_path(1), low_charging_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_critical_state_for_high_battery_temperature_when_unplugged) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(WakeUp(&request_processed)); auto exploding_battery = discharging_battery; exploding_battery.temperature = exploding_temperature; fake_upower.change_device(device_path(1), exploding_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line( {"critical", "temperature", std::to_string(exploding_battery.temperature).substr(0,4)})); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_critical_state_for_high_battery_temperature_when_plugged) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(WakeUp(&request_processed)); auto exploding_battery = charging_battery; exploding_battery.temperature = exploding_temperature; fake_upower.change_device(device_path(0), plugged_line_power); fake_upower.change_device(display_device_path, charging_battery); fake_upower.change_device(device_path(1), exploding_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line( {"critical", "temperature", std::to_string(exploding_battery.temperature).substr(0,4)})); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_critical_state_for_high_temperature_of_battery_added_after_startup) { fake_upower.add_device(device_path(2), full_battery); wait_for_tracked_batteries({device_path(1), device_path(2)}); rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(WakeUp(&request_processed)); auto exploding_battery = charging_battery; exploding_battery.temperature = exploding_temperature; fake_upower.change_device(device_path(2), exploding_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_critical_state_for_high_temperature_of_removed_battery) { EXPECT_CALL(mock_handlers, power_source_critical()).Times(0); auto removed_battery = full_battery; removed_battery.is_present = false; removed_battery.temperature = exploding_temperature; fake_upower.change_device(device_path(1), removed_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_critical_state_for_high_temperature_of_display_device) { EXPECT_CALL(mock_handlers, power_source_critical()).Times(0); auto exploding_battery = full_battery; exploding_battery.temperature = exploding_temperature; fake_upower.change_device(display_device_path, exploding_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_critical_state_for_low_energy_of_removed_battery) { EXPECT_CALL(mock_handlers, power_source_critical()).Times(0); auto removed_battery = full_battery; removed_battery.is_present = false; removed_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, removed_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_of_presence_changes_for_non_display_devices) { EXPECT_CALL(mock_handlers, power_source_change()).Times(0); fake_upower.add_device(device_path(2), full_battery); wait_for_tracked_batteries({device_path(1), device_path(2)}); auto removed_battery = full_battery; removed_battery.is_present = false; fake_upower.change_device(device_path(1), removed_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLid, does_not_notify_again_of_critical_state_for_low_energy_if_already_critical) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(WakeUp(&request_processed)); auto low_battery = discharging_battery; low_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, low_battery); low_battery.percentage = critical_percentage / 2.0; fake_upower.change_device(display_device_path, low_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, notifies_again_of_critical_state_for_low_energy_if_has_seen_non_critical_percentage) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(Return()) .WillOnce(WakeUp(&request_processed)); auto low_battery = discharging_battery; low_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, low_battery); low_battery.percentage = non_critical_percentage; fake_upower.change_device(display_device_path, low_battery); low_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, low_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLidWithAlmostEmptyBattery, does_not_notify_of_critical_state_for_low_energy) { EXPECT_CALL(mock_handlers, power_source_critical()).Times(0); upower_power_source_and_lid.start_processing(); auto low_battery = discharging_battery; low_battery.percentage = critical_percentage / 2.0; fake_upower.change_device(display_device_path, low_battery); std::this_thread::sleep_for(100ms); } TEST_F(AUPowerPowerSourceAndLidWithAlmostEmptyBattery, notifies_of_critical_state_for_low_energy_if_has_seen_non_critical_percentage) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, power_source_critical()) .WillOnce(WakeUp(&request_processed)); upower_power_source_and_lid.start_processing(); auto low_battery = discharging_battery; low_battery.percentage = non_critical_percentage; fake_upower.change_device(display_device_path, low_battery); low_battery.percentage = critical_percentage; fake_upower.change_device(display_device_path, low_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_lid_closed) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, lid(repowerd::LidState::closed)) .WillOnce(WakeUp(&request_processed)); fake_upower.close_lid(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line({"lid_is_closed", "true"})); } TEST_F(AUPowerPowerSourceAndLid, notifies_of_lid_open) { rt::WaitCondition request_processed; EXPECT_CALL(mock_handlers, lid(repowerd::LidState::open)) .WillOnce(WakeUp(&request_processed)); fake_upower.open_lid(); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); EXPECT_TRUE(fake_log.contains_line({"lid_is_closed", "false"})); } TEST_F(AUPowerPowerSourceAndLid, second_start_processing_is_ignored) { auto prev_num_calls = fake_upower.num_enumerate_devices_calls(); upower_power_source_and_lid.start_processing(); EXPECT_THAT(fake_upower.num_enumerate_devices_calls(), Eq(prev_num_calls)); } TEST_F(AUPowerPowerSourceAndLid, inhibits_suspend_temporarily_on_change) { rt::WaitCondition request_processed; EXPECT_CALL(mock_temporary_suspend_inhibition, inhibit_suspend_for(2000ms, _)) .WillOnce(WakeUp(&request_processed)); fake_upower.change_device(display_device_path, discharging_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } TEST_F(AUPowerPowerSourceAndLid, inhibits_suspend_temporarily_on_critical_state) { rt::WaitCondition request_processed; EXPECT_CALL(mock_temporary_suspend_inhibition, inhibit_suspend_for(2000ms, _)) .WillOnce(WakeUp(&request_processed)); auto exploding_battery = full_battery; exploding_battery.temperature = exploding_temperature; fake_upower.change_device(device_path(1), exploding_battery); request_processed.wait_for(default_timeout); EXPECT_TRUE(request_processed.woken()); } repowerd-2023.07/tests/adapter-tests/unity_screen_dbus_client.cpp000066400000000000000000000111371446034100200252230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "unity_screen_dbus_client.h" #include namespace rt = repowerd::test; rt::UnityScreenDBusClient::UnityScreenDBusClient(std::string const& address) : rt::DBusClient{ address, "com.canonical.Unity.Screen", "/com/canonical/Unity/Screen"} { } rt::DBusAsyncReplyString rt::UnityScreenDBusClient::request_introspection() { return invoke_with_reply( "org.freedesktop.DBus.Introspectable", "Introspect", nullptr); } rt::DBusAsyncReplyVoid rt::UnityScreenDBusClient::request_set_user_brightness(int32_t brightness) { return invoke_with_reply( unity_screen_interface, "setUserBrightness", g_variant_new("(i)", brightness)); } rt::DBusAsyncReplyVoid rt::UnityScreenDBusClient::request_user_auto_brightness_enable(bool enabled) { gboolean const e = enabled ? TRUE : FALSE; return invoke_with_reply( unity_screen_interface, "userAutobrightnessEnable", g_variant_new("(b)", e)); } rt::DBusAsyncReplyVoid rt::UnityScreenDBusClient::request_set_inactivity_timeouts( int32_t poweroff_timeout, int32_t dimmer_timeout) { return invoke_with_reply( unity_screen_interface, "setInactivityTimeouts", g_variant_new("(ii)", poweroff_timeout, dimmer_timeout)); } rt::DBusAsyncReplyVoid rt::UnityScreenDBusClient::request_set_touch_visualization_enabled(bool enabled) { gboolean const e = enabled ? TRUE : FALSE; return invoke_with_reply( unity_screen_interface, "setTouchVisualizationEnabled", g_variant_new("(b)", e)); } rt::DBusAsyncReplyBool rt::UnityScreenDBusClient::request_set_screen_power_mode( std::string const& mode, int reason) { auto mode_cstr = mode.c_str(); return invoke_with_reply( unity_screen_interface, "setScreenPowerMode", g_variant_new("(si)", mode_cstr, reason)); } rt::DBusAsyncReplyInt rt::UnityScreenDBusClient::request_keep_display_on() { return invoke_with_reply( unity_screen_interface, "keepDisplayOn", nullptr); } rt::DBusAsyncReplyVoid rt::UnityScreenDBusClient::request_remove_display_on_request(int id) { return invoke_with_reply( unity_screen_interface, "removeDisplayOnRequest", g_variant_new("(i)", id)); } rt::DBusAsyncReply rt::UnityScreenDBusClient::request_invalid_method() { return invoke_with_reply( unity_screen_interface, "invalidMethod", nullptr); } rt::DBusAsyncReply rt::UnityScreenDBusClient::request_method_with_invalid_arguments() { char const* const str = "abcd"; return invoke_with_reply( unity_screen_interface, "setUserBrightness", g_variant_new("(s)", str)); } rt::DBusAsyncReply rt::UnityScreenDBusClient::request_method_with_invalid_interface() { int const brightness = 10; return invoke_with_reply( "com.invalid.Interface", "setUserBrightness", g_variant_new("(i)", brightness)); } repowerd::HandlerRegistration rt::UnityScreenDBusClient::register_display_power_state_change_handler( std::function const& func) { return event_loop.register_signal_handler( connection, nullptr, "com.canonical.Unity.Screen", "DisplayPowerStateChange", "/com/canonical/Unity/Screen", [func] ( GDBusConnection* /*connection*/, gchar const* /*sender*/, gchar const* /*object_path*/, gchar const* /*interface_name*/, gchar const* /*signal_name*/, GVariant* parameters) { int32_t power_state{-1}; int32_t reason{-1}; g_variant_get(parameters, "(ii)", &power_state, &reason); func({power_state, reason}); }); } repowerd-2023.07/tests/adapter-tests/unity_screen_dbus_client.h000066400000000000000000000037171446034100200246750ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "dbus_client.h" namespace repowerd { namespace test { class UnityScreenDBusClient : public DBusClient { public: UnityScreenDBusClient(std::string const& address); DBusAsyncReplyString request_introspection(); DBusAsyncReplyVoid request_set_user_brightness(int32_t brightness); DBusAsyncReplyVoid request_user_auto_brightness_enable(bool enabled); DBusAsyncReplyVoid request_set_inactivity_timeouts( int32_t poweroff_timeout, int32_t dimmer_timeout); DBusAsyncReplyVoid request_set_touch_visualization_enabled(bool enabled); DBusAsyncReplyBool request_set_screen_power_mode( std::string const& mode, int reason); DBusAsyncReplyInt request_keep_display_on(); DBusAsyncReplyVoid request_remove_display_on_request(int id); DBusAsyncReply request_invalid_method(); DBusAsyncReply request_method_with_invalid_arguments(); DBusAsyncReply request_method_with_invalid_interface(); char const* const unity_screen_interface = "com.canonical.Unity.Screen"; struct DisplayPowerStateChangeParams { int32_t power_state; int32_t reason; }; HandlerRegistration register_display_power_state_change_handler( std::function const& f); }; } } repowerd-2023.07/tests/common/000077500000000000000000000000001446034100200161425ustar00rootroot00000000000000repowerd-2023.07/tests/common/CMakeLists.txt000066400000000000000000000016211446034100200207020ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis add_library( repowerd-test-common STATIC fake_log.cpp fake_system_power_control.cpp spin_wait.cpp ) target_link_libraries( repowerd-test-common repowerd-core ${GTEST_LIBRARY} ${GMOCK_LIBRARIES} ) repowerd-2023.07/tests/common/fake_log.cpp000066400000000000000000000037311446034100200204210ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_log.h" #include #include namespace rt = repowerd::test; namespace { bool get_log_to_console() { auto const test_log_cstr = getenv("REPOWERD_TEST_LOG"); auto const test_log = test_log_cstr ? std::string{test_log_cstr} : ""; return test_log == "console"; } } rt::FakeLog::FakeLog(repowerd::LogLevel threshold) : repowerd::Log::Log(threshold), log_to_console{get_log_to_console()} { } void rt::FakeLog::logOutput(repowerd::LogLevel, char const* tag, char const* format, va_list ap) { std::string const format_str = std::string{tag} + ": " + format + "\n"; char output[1024]; vsnprintf(output, 1024, format_str.c_str(), ap); std::lock_guard lock{contents_mutex}; contents.push_back(output); if (log_to_console) printf("%s", output); } bool rt::FakeLog::contains_line(std::vector const& words) { std::lock_guard lock{contents_mutex}; for (auto const& line : contents) { bool found = true; for (auto const& word : words) { if (line.find(word) == std::string::npos) { found = false; break; } } if (found) return true; } return false; } repowerd-2023.07/tests/common/fake_log.h000066400000000000000000000022531446034100200200640ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/log.h" #include #include #include namespace repowerd { namespace test { class FakeLog : public Log { public: FakeLog(repowerd::LogLevel threshold); void logOutput(LogLevel level, char const* tag, char const* format, va_list ap) override; bool contains_line(std::vector const& words); private: bool const log_to_console; std::mutex contents_mutex; std::vector contents; }; } } repowerd-2023.07/tests/common/fake_shared.h000066400000000000000000000016431446034100200205530ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { namespace test { struct NullDeleter { void operator()(void*){} }; template std::shared_ptr fake_shared(Type& t) { return {&t, NullDeleter()}; } } } repowerd-2023.07/tests/common/fake_system_power_control.cpp000066400000000000000000000107531446034100200241420ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_system_power_control.h" namespace rt = repowerd::test; namespace { char const* const suspend_id = "FakeSystemPowerControl"; } rt::FakeSystemPowerControl::FakeSystemPowerControl() : are_default_system_handlers_allowed_{true}, system_resume_handler{[]{}} { } void rt::FakeSystemPowerControl::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeSystemPowerControl::register_system_resume_handler( SystemResumeHandler const& handler) { mock.register_system_resume_handler(handler); this->system_resume_handler = handler; return HandlerRegistration{ [this] { mock.unregister_system_resume_handler(); std::lock_guard lock{mutex}; this->system_resume_handler = []{}; }}; } repowerd::HandlerRegistration rt::FakeSystemPowerControl::register_system_allow_suspend_handler( SystemAllowSuspendHandler const& handler) { mock.register_system_allow_suspend_handler(handler); this->system_allow_suspend_handler = handler; return HandlerRegistration{ [this] { mock.unregister_system_allow_suspend_handler(); std::lock_guard lock{mutex}; this->system_allow_suspend_handler = [](auto){}; }}; } repowerd::HandlerRegistration rt::FakeSystemPowerControl::register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const& handler) { mock.register_system_disallow_suspend_handler(handler); this->system_disallow_suspend_handler = handler; return HandlerRegistration{ [this] { mock.unregister_system_disallow_suspend_handler(); std::lock_guard lock{mutex}; this->system_disallow_suspend_handler = [](auto){}; }}; } void rt::FakeSystemPowerControl::allow_automatic_suspend(std::string const& id) { mock.allow_automatic_suspend(id); std::lock_guard lock{mutex}; automatic_suspend_disallowances.erase(id); } void rt::FakeSystemPowerControl::disallow_automatic_suspend(std::string const& id) { mock.disallow_automatic_suspend(id); std::lock_guard lock{mutex}; automatic_suspend_disallowances.insert(id); } void rt::FakeSystemPowerControl::power_off() { mock.power_off(); } void rt::FakeSystemPowerControl::suspend() { mock.suspend(); } void rt::FakeSystemPowerControl::allow_default_system_handlers() { mock.allow_default_system_handlers(); std::lock_guard lock{mutex}; are_default_system_handlers_allowed_ = true; } void rt::FakeSystemPowerControl::disallow_default_system_handlers() { mock.disallow_default_system_handlers(); std::lock_guard lock{mutex}; are_default_system_handlers_allowed_ = false; } bool rt::FakeSystemPowerControl::is_automatic_suspend_allowed() { std::lock_guard lock{mutex}; return automatic_suspend_disallowances.empty(); } bool rt::FakeSystemPowerControl::are_default_system_handlers_allowed() { std::lock_guard lock{mutex}; return are_default_system_handlers_allowed_; } void rt::FakeSystemPowerControl::emit_system_resume() { SystemResumeHandler handler; { std::lock_guard lock{mutex}; handler = system_resume_handler; } handler(); } void rt::FakeSystemPowerControl::emit_system_allow_suspend() { SystemAllowSuspendHandler handler; { std::lock_guard lock{mutex}; handler = system_allow_suspend_handler; } handler(suspend_id); } void rt::FakeSystemPowerControl::emit_system_disallow_suspend() { SystemDisallowSuspendHandler handler; { std::lock_guard lock{mutex}; handler = system_disallow_suspend_handler; } handler(suspend_id); } repowerd-2023.07/tests/common/fake_system_power_control.h000066400000000000000000000063321446034100200236050ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/system_power_control.h" #include #include #include namespace repowerd { namespace test { class FakeSystemPowerControl : public SystemPowerControl { public: FakeSystemPowerControl(); void start_processing() override; HandlerRegistration register_system_resume_handler( SystemResumeHandler const& systemd_resume_handler) override; HandlerRegistration register_system_allow_suspend_handler( SystemAllowSuspendHandler const& system_allow_suspend_handler) override; HandlerRegistration register_system_disallow_suspend_handler( SystemDisallowSuspendHandler const& system_disallow_suspend_handler) override; void allow_automatic_suspend(std::string const& id) override; void disallow_automatic_suspend(std::string const& id) override; void power_off() override; void suspend() override; void allow_default_system_handlers() override; void disallow_default_system_handlers() override; bool is_automatic_suspend_allowed(); bool are_default_system_handlers_allowed(); void emit_system_resume(); void emit_system_allow_suspend(); void emit_system_disallow_suspend(); struct MockMethods { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_system_resume_handler, void(SystemResumeHandler const&)); MOCK_METHOD0(unregister_system_resume_handler, void()); MOCK_METHOD1(register_system_allow_suspend_handler, void(SystemAllowSuspendHandler const&)); MOCK_METHOD0(unregister_system_allow_suspend_handler, void()); MOCK_METHOD1(register_system_disallow_suspend_handler, void(SystemDisallowSuspendHandler const&)); MOCK_METHOD0(unregister_system_disallow_suspend_handler, void()); MOCK_METHOD1(allow_automatic_suspend, void(std::string const&)); MOCK_METHOD1(disallow_automatic_suspend, void(std::string const&)); MOCK_METHOD0(power_off, void()); MOCK_METHOD0(suspend, void()); MOCK_METHOD0(allow_default_system_handlers, void()); MOCK_METHOD0(disallow_default_system_handlers, void()); }; testing::NiceMock mock; private: std::mutex mutex; std::unordered_set automatic_suspend_disallowances; bool are_default_system_handlers_allowed_; SystemResumeHandler system_resume_handler; SystemAllowSuspendHandler system_allow_suspend_handler; SystemDisallowSuspendHandler system_disallow_suspend_handler; }; } } repowerd-2023.07/tests/common/spin_wait.cpp000066400000000000000000000023231446034100200206430ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "spin_wait.h" #include bool repowerd::test::spin_wait_for_condition_or_timeout( std::function const& condition, std::chrono::milliseconds timeout, std::chrono::milliseconds spin_period) { auto const end = std::chrono::steady_clock::now() + timeout; bool condition_fulfilled = false; while (std::chrono::steady_clock::now() < end && !(condition_fulfilled = condition())) { std::this_thread::sleep_for(spin_period); } return condition_fulfilled; } repowerd-2023.07/tests/common/spin_wait.h000066400000000000000000000017531446034100200203160ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include namespace repowerd { namespace test { bool spin_wait_for_condition_or_timeout( std::function const& condition, std::chrono::milliseconds timeout, std::chrono::milliseconds spin_period = std::chrono::milliseconds{10}); } } repowerd-2023.07/tests/common/wait_condition.h000066400000000000000000000030011446034100200213170ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include #include #include #include namespace repowerd { namespace test { struct WaitCondition { void wait_for(std::chrono::milliseconds msec) { std::unique_lock ul(guard); condition.wait_for(ul, msec, [this] { return woken_; }); } void wake_up() { std::lock_guard ul(guard); woken_ = true; condition.notify_all(); } bool woken() { std::lock_guard ul(guard); return woken_; } private: std::mutex guard; std::condition_variable condition; bool woken_ = false; }; ACTION_P(WakeUp, wait_condition) { wait_condition->wake_up(); } ACTION_P2(WaitFor, wait_condition, delay) { wait_condition->wait_for(delay); } } } repowerd-2023.07/tests/core-tests/000077500000000000000000000000001446034100200167425ustar00rootroot00000000000000repowerd-2023.07/tests/core-tests/CMakeLists.txt000066400000000000000000000035471446034100200215130ustar00rootroot00000000000000# Copyright © 2016 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Alexandros Frantzis add_executable( repowerd-core-tests acceptance_test.cpp daemon_config.cpp fake_display_information.cpp fake_client_requests.cpp fake_client_settings.cpp fake_lid.cpp fake_notification_service.cpp fake_power_button.cpp fake_power_source.cpp fake_proximity_sensor.cpp fake_session_tracker.cpp fake_state_machine_options.cpp fake_timer.cpp fake_user_activity.cpp fake_voice_call_service.cpp run_daemon.cpp test_client_requests.cpp test_client_settings.cpp test_treat_power_button_as_user_activity.cpp test_daemon.cpp test_fake_timer.cpp test_handler_registration.cpp test_lid.cpp test_modem_power_control.cpp test_notification.cpp test_performance_booster.cpp test_power_button.cpp test_power_source.cpp test_proximity_sensor.cpp test_session.cpp test_system_power_control.cpp test_turn_on_display_at_startup.cpp test_user_activity.cpp test_voice_call.cpp ) target_link_libraries( repowerd-core-tests repowerd-core repowerd-test-common ${GTEST_LIBRARY} ${GMOCK_LIBRARIES} ) add_test(repowerd-core-tests ${EXECUTABLE_OUTPUT_PATH}/repowerd-core-tests) repowerd-2023.07/tests/core-tests/acceptance_test.cpp000066400000000000000000000376171446034100200226110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "run_daemon.h" #include "daemon_config.h" #include "mock_brightness_control.h" #include "mock_display_power_control.h" #include "mock_display_power_event_sink.h" #include "mock_power_button_event_sink.h" #include "fake_client_requests.h" #include "fake_client_settings.h" #include "fake_lid.h" #include "fake_log.h" #include "fake_notification_service.h" #include "fake_power_button.h" #include "fake_power_source.h" #include "fake_proximity_sensor.h" #include "fake_session_tracker.h" #include "fake_system_power_control.h" #include "fake_timer.h" #include "fake_user_activity.h" #include "fake_voice_call_service.h" #include "src/core/daemon.h" #include "src/core/infinite_timeout.h" #include "src/core/state_machine_options.h" #include #include namespace rt = repowerd::test; using namespace testing; rt::AcceptanceTest::AcceptanceTest() : AcceptanceTestBase{std::make_shared()} { run_daemon(); } rt::AcceptanceTestBase::AcceptanceTestBase( std::shared_ptr const& daemon_config_ptr) : config_ptr{daemon_config_ptr}, config{*daemon_config_ptr}, notification_expiration_timeout{ config.the_state_machine_options()->notification_expiration_timeout()}, power_button_long_press_timeout{ config.the_state_machine_options()->power_button_long_press_timeout()}, user_inactivity_normal_display_dim_duration{ config.the_state_machine_options()->user_inactivity_normal_display_dim_duration()}, user_inactivity_normal_display_dim_timeout{ config.the_state_machine_options()->user_inactivity_normal_display_off_timeout() - config.the_state_machine_options()->user_inactivity_normal_display_dim_duration()}, user_inactivity_normal_display_off_timeout{ config.the_state_machine_options()->user_inactivity_normal_display_off_timeout()}, user_inactivity_normal_suspend_timeout{ config.the_state_machine_options()->user_inactivity_normal_suspend_timeout()}, user_inactivity_post_notification_display_off_timeout{ config.the_state_machine_options()->user_inactivity_post_notification_display_off_timeout()}, user_inactivity_reduced_display_off_timeout{ config.the_state_machine_options()->user_inactivity_reduced_display_off_timeout()}, infinite_timeout{repowerd::infinite_timeout}, default_session_id{ config.the_fake_session_tracker()->default_session()} { } rt::AcceptanceTestBase::~AcceptanceTestBase() { daemon.flush(); daemon.stop(); if (daemon_thread.joinable()) daemon_thread.join(); } void rt::AcceptanceTestBase::run_daemon() { daemon_thread = rt::run_daemon(daemon); } void rt::AcceptanceTestBase::expect_autobrightness_disabled() { EXPECT_CALL(*config.the_mock_brightness_control(), disable_autobrightness()); } void rt::AcceptanceTestBase::expect_autobrightness_enabled() { EXPECT_CALL(*config.the_mock_brightness_control(), enable_autobrightness()); } void rt::AcceptanceTestBase::expect_display_turns_off() { EXPECT_CALL(*config.the_mock_brightness_control(), set_off_brightness()); EXPECT_CALL(*config.the_mock_display_power_control(), turn_off(DisplayPowerControlFilter::all)); } void rt::AcceptanceTestBase::expect_display_turns_on() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_on(DisplayPowerControlFilter::all)); EXPECT_CALL(*config.the_mock_brightness_control(), set_normal_brightness()); } void rt::AcceptanceTestBase::expect_display_dims() { EXPECT_CALL(*config.the_mock_brightness_control(), set_dim_brightness()); } void rt::AcceptanceTestBase::expect_display_brightens() { EXPECT_CALL(*config.the_mock_brightness_control(), set_normal_brightness()); } void rt::AcceptanceTestBase::expect_internal_display_turns_off() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_off(DisplayPowerControlFilter::internal)); } void rt::AcceptanceTestBase::expect_internal_display_turns_on() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_on(DisplayPowerControlFilter::internal)); } void rt::AcceptanceTestBase::expect_external_display_turns_on() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_on(DisplayPowerControlFilter::external)); } void rt::AcceptanceTestBase::expect_long_press_notification() { EXPECT_CALL(*config.the_mock_power_button_event_sink(), notify_long_press()); } void rt::AcceptanceTestBase::expect_no_autobrightness_change() { EXPECT_CALL(*config.the_mock_brightness_control(), disable_autobrightness()).Times(0); EXPECT_CALL(*config.the_mock_brightness_control(), enable_autobrightness()).Times(0); } void rt::AcceptanceTestBase::expect_no_display_brightness_change() { EXPECT_CALL(*config.the_mock_brightness_control(), set_dim_brightness()).Times(0); EXPECT_CALL(*config.the_mock_brightness_control(), set_normal_brightness()).Times(0); EXPECT_CALL(*config.the_mock_brightness_control(), set_off_brightness()).Times(0); EXPECT_CALL(*config.the_mock_brightness_control(), set_normal_brightness_value(_)).Times(0); } void rt::AcceptanceTestBase::expect_no_display_power_change() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_on(_)).Times(0); EXPECT_CALL(*config.the_mock_display_power_control(), turn_off(_)).Times(0); } void rt::AcceptanceTestBase::expect_no_long_press_notification() { EXPECT_CALL(*config.the_mock_power_button_event_sink(), notify_long_press()).Times(0); } void rt::AcceptanceTestBase::expect_no_system_power_change() { EXPECT_CALL(config.the_fake_system_power_control()->mock, power_off()).Times(0); EXPECT_CALL(config.the_fake_system_power_control()->mock, suspend()).Times(0); } void rt::AcceptanceTestBase::expect_normal_brightness_value_set_to(double value) { EXPECT_CALL(*config.the_mock_brightness_control(), set_normal_brightness_value(value)); } void rt::AcceptanceTestBase::expect_display_power_off_notification( DisplayPowerChangeReason reason) { EXPECT_CALL(*config.the_mock_display_power_event_sink(), notify_display_power_off(reason)); } void rt::AcceptanceTestBase::expect_display_power_on_notification( DisplayPowerChangeReason reason) { EXPECT_CALL(*config.the_mock_display_power_event_sink(), notify_display_power_on(reason)); } void rt::AcceptanceTestBase::expect_system_powers_off() { EXPECT_CALL(config.the_fake_system_power_control()->mock, power_off()); } void rt::AcceptanceTestBase::expect_system_suspends() { EXPECT_CALL(config.the_fake_system_power_control()->mock, suspend()); } bool rt::AcceptanceTestBase::log_contains_line(std::vector const& words) { return config.the_fake_log()->contains_line(words); } void rt::AcceptanceTestBase::verify_expectations() { daemon.flush(); testing::Mock::VerifyAndClearExpectations(config.the_mock_brightness_control().get()); testing::Mock::VerifyAndClearExpectations(config.the_mock_display_power_control().get()); testing::Mock::VerifyAndClearExpectations(config.the_mock_power_button_event_sink().get()); } void rt::AcceptanceTestBase::advance_time_by(std::chrono::milliseconds advance) { daemon.flush(); config.the_fake_timer()->advance_by(advance); daemon.flush(); } void rt::AcceptanceTestBase::client_request_disable_inactivity_timeout( std::string const& id, pid_t pid) { config.the_fake_client_requests()->emit_disable_inactivity_timeout(id, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_enable_inactivity_timeout( std::string const& id, pid_t pid) { config.the_fake_client_requests()->emit_enable_inactivity_timeout(id, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_set_inactivity_timeout( std::chrono::milliseconds timeout, pid_t pid) { config.the_fake_client_requests()->emit_set_inactivity_timeout(timeout, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_disable_autobrightness(pid_t pid) { config.the_fake_client_requests()->emit_disable_autobrightness(pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_enable_autobrightness(pid_t pid) { config.the_fake_client_requests()->emit_enable_autobrightness(pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_set_normal_brightness_value(double value, pid_t pid) { config.the_fake_client_requests()->emit_set_normal_brightness_value(value, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_allow_suspend( std::string const& id, pid_t pid) { config.the_fake_client_requests()->emit_allow_suspend(id, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_request_disallow_suspend( std::string const& id, pid_t pid) { config.the_fake_client_requests()->emit_disallow_suspend(id, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_setting_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid) { config.the_fake_client_settings()->emit_set_inactivity_behavior( power_action, power_supply, timeout, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_setting_set_lid_behavior( PowerAction power_action, PowerSupply power_supply, pid_t pid) { config.the_fake_client_settings()->emit_set_lid_behavior( power_action, power_supply, pid); daemon.flush(); } void rt::AcceptanceTestBase::client_setting_set_critical_power_behavior( PowerAction power_action, pid_t pid) { config.the_fake_client_settings()->emit_set_critical_power_behavior( power_action, pid); daemon.flush(); } void rt::AcceptanceTestBase::close_lid() { config.the_fake_lid()->close(); daemon.flush(); } void rt::AcceptanceTestBase::emit_notification(std::string const& id) { config.the_fake_notification_service()->emit_notification(id); daemon.flush(); } void rt::AcceptanceTestBase::emit_notification_done(std::string const& id) { config.the_fake_notification_service()->emit_notification_done(id); daemon.flush(); } void rt::AcceptanceTestBase::emit_notification() { emit_notification("AcceptanceTestBaseId"); } void rt::AcceptanceTestBase::emit_notification_done() { emit_notification_done("AcceptanceTestBaseId"); } void rt::AcceptanceTestBase::emit_power_source_change() { config.the_fake_power_source()->emit_power_source_change(); daemon.flush(); } void rt::AcceptanceTestBase::emit_power_source_critical() { config.the_fake_power_source()->emit_power_source_critical(); daemon.flush(); } void rt::AcceptanceTestBase::emit_proximity_state_far() { config.the_fake_proximity_sensor()->emit_proximity_state( repowerd::ProximityState::far); daemon.flush(); } void rt::AcceptanceTestBase::emit_proximity_state_far_if_enabled() { config.the_fake_proximity_sensor()->emit_proximity_state_if_enabled( repowerd::ProximityState::far); } void rt::AcceptanceTestBase::emit_proximity_state_near() { config.the_fake_proximity_sensor()->emit_proximity_state( repowerd::ProximityState::near); daemon.flush(); } void rt::AcceptanceTestBase::emit_proximity_state_near_if_enabled() { config.the_fake_proximity_sensor()->emit_proximity_state_if_enabled( repowerd::ProximityState::near); } void rt::AcceptanceTestBase::emit_system_allow_suspend() { config.the_fake_system_power_control()->emit_system_allow_suspend(); daemon.flush(); } void rt::AcceptanceTestBase::emit_system_disallow_suspend() { config.the_fake_system_power_control()->emit_system_disallow_suspend(); daemon.flush(); } void rt::AcceptanceTestBase::emit_active_call() { config.the_fake_voice_call_service()->emit_active_call(); daemon.flush(); } void rt::AcceptanceTestBase::emit_no_active_call() { config.the_fake_voice_call_service()->emit_no_active_call(); daemon.flush(); } void rt::AcceptanceTestBase::open_lid() { config.the_fake_lid()->open(); daemon.flush(); } void rt::AcceptanceTestBase::perform_user_activity_extending_power_state() { config.the_fake_user_activity()->perform( repowerd::UserActivityType::extend_power_state); daemon.flush(); } void rt::AcceptanceTestBase::perform_user_activity_changing_power_state() { config.the_fake_user_activity()->perform( repowerd::UserActivityType::change_power_state); daemon.flush(); } void rt::AcceptanceTestBase::press_power_button() { config.the_fake_power_button()->press(); daemon.flush(); } void rt::AcceptanceTestBase::release_power_button() { config.the_fake_power_button()->release(); daemon.flush(); } void rt::AcceptanceTestBase::set_proximity_state_far() { config.the_fake_proximity_sensor()->set_proximity_state( repowerd::ProximityState::far); } void rt::AcceptanceTestBase::set_proximity_state_near() { config.the_fake_proximity_sensor()->set_proximity_state( repowerd::ProximityState::near); } void rt::AcceptanceTestBase::add_compatible_session(std::string const& session_id, pid_t pid) { config.the_fake_session_tracker()->add_session( session_id, SessionType::RepowerdCompatible, pid); daemon.flush(); } void rt::AcceptanceTestBase::add_incompatible_session(std::string const& session_id, pid_t pid) { config.the_fake_session_tracker()->add_session( session_id, SessionType::RepowerdIncompatible, pid); daemon.flush(); } void rt::AcceptanceTestBase::switch_to_session(std::string const& session_id) { config.the_fake_session_tracker()->switch_to_session(session_id); daemon.flush(); } void rt::AcceptanceTestBase::remove_session(std::string const& session_id) { config.the_fake_session_tracker()->remove_session(session_id); daemon.flush(); } void rt::AcceptanceTestBase::turn_off_display() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_off(DisplayPowerControlFilter::all)); EXPECT_CALL(*config.the_mock_brightness_control(), set_off_brightness()); press_power_button(); release_power_button(); daemon.flush(); testing::Mock::VerifyAndClearExpectations(config.the_mock_display_power_control().get()); testing::Mock::VerifyAndClearExpectations(config.the_mock_brightness_control().get()); } void rt::AcceptanceTestBase::turn_on_display() { EXPECT_CALL(*config.the_mock_display_power_control(), turn_on(DisplayPowerControlFilter::all)); EXPECT_CALL(*config.the_mock_brightness_control(), set_normal_brightness()); press_power_button(); release_power_button(); daemon.flush(); testing::Mock::VerifyAndClearExpectations(config.the_mock_display_power_control().get()); testing::Mock::VerifyAndClearExpectations(config.the_mock_brightness_control().get()); } void rt::AcceptanceTestBase::use_battery_power() { config.the_fake_power_source()->set_is_using_battery_power(true); } void rt::AcceptanceTestBase::use_line_power() { config.the_fake_power_source()->set_is_using_battery_power(false); } bool rt::AcceptanceTestBase::are_proximity_events_enabled() { return config.the_fake_proximity_sensor()->are_proximity_events_enabled(); } bool rt::AcceptanceTestBase::are_default_system_handlers_allowed() { return config.the_fake_system_power_control()->are_default_system_handlers_allowed(); } repowerd-2023.07/tests/core-tests/acceptance_test.h000066400000000000000000000133261446034100200222450ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/daemon.h" #include "src/core/display_power_change_reason.h" #include "src/core/power_action.h" #include "src/core/power_supply.h" #include "daemon_config.h" #include "default_pid.h" #include #include #include #include namespace repowerd { namespace test { struct AcceptanceTestBase { AcceptanceTestBase(std::shared_ptr const& daemon_config); ~AcceptanceTestBase(); void run_daemon(); void expect_autobrightness_disabled(); void expect_autobrightness_enabled(); void expect_display_turns_off(); void expect_display_turns_on(); void expect_display_dims(); void expect_display_brightens(); void expect_external_display_turns_on(); void expect_internal_display_turns_off(); void expect_internal_display_turns_on(); void expect_long_press_notification(); void expect_no_autobrightness_change(); void expect_no_display_power_change(); void expect_no_display_brightness_change(); void expect_no_long_press_notification(); void expect_no_system_power_change(); void expect_normal_brightness_value_set_to(double); void expect_display_power_off_notification(DisplayPowerChangeReason); void expect_display_power_on_notification(DisplayPowerChangeReason); void expect_system_powers_off(); void expect_system_suspends(); void verify_expectations(); void advance_time_by(std::chrono::milliseconds advance); void client_request_disable_inactivity_timeout( std::string const& id = "AcceptanceTestId", pid_t pid = default_pid); void client_request_enable_inactivity_timeout( std::string const& id = "AcceptanceTestId", pid_t pid = default_pid); void client_request_set_inactivity_timeout( std::chrono::milliseconds timeout, pid_t pid = default_pid); void client_request_disable_autobrightness(pid_t pid = default_pid); void client_request_enable_autobrightness(pid_t pid = default_pid); void client_request_set_normal_brightness_value(double value, pid_t pid = default_pid); void client_request_allow_suspend( std::string const& id = "AcceptanceTestId", pid_t pid = default_pid); void client_request_disallow_suspend( std::string const& id = "AcceptanceTestId", pid_t pid = default_pid); void client_setting_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid = default_pid); void client_setting_set_lid_behavior( PowerAction power_action, PowerSupply power_supply, pid_t pid = default_pid); void client_setting_set_critical_power_behavior( PowerAction power_action, pid_t pid = default_pid); void close_lid(); void emit_notification(std::string const& id); void emit_notification_done(std::string const& id); void emit_notification(); void emit_notification_done(); void emit_power_source_change(); void emit_power_source_critical(); void emit_proximity_state_far(); void emit_proximity_state_far_if_enabled(); void emit_proximity_state_near(); void emit_proximity_state_near_if_enabled(); void emit_system_allow_suspend(); void emit_system_disallow_suspend(); void emit_active_call(); void emit_no_active_call(); void open_lid(); void perform_user_activity_extending_power_state(); void perform_user_activity_changing_power_state(); void press_power_button(); void release_power_button(); void set_proximity_state_far(); void set_proximity_state_near(); void add_compatible_session(std::string const& session_id, pid_t pid); void add_incompatible_session(std::string const& session_id, pid_t pid); void switch_to_session(std::string const& session_id); void remove_session(std::string const& session_id); void turn_off_display(); void turn_on_display(); void use_battery_power(); void use_line_power(); bool log_contains_line(std::vector const& words); bool are_proximity_events_enabled(); bool are_default_system_handlers_allowed(); std::shared_ptr config_ptr; DaemonConfig& config; Daemon daemon{config}; std::thread daemon_thread; std::chrono::milliseconds const notification_expiration_timeout; std::chrono::milliseconds const power_button_long_press_timeout; std::chrono::milliseconds const user_inactivity_normal_display_dim_duration; std::chrono::milliseconds const user_inactivity_normal_display_dim_timeout; std::chrono::milliseconds const user_inactivity_normal_display_off_timeout; std::chrono::milliseconds const user_inactivity_normal_suspend_timeout; std::chrono::milliseconds const user_inactivity_post_notification_display_off_timeout; std::chrono::milliseconds const user_inactivity_reduced_display_off_timeout; std::chrono::milliseconds const infinite_timeout; std::string const default_session_id; }; struct AcceptanceTest : AcceptanceTestBase, testing::Test { AcceptanceTest(); }; } } repowerd-2023.07/tests/core-tests/daemon_config.cpp000066400000000000000000000223271446034100200222440ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "daemon_config.h" #include "src/core/default_state_machine_factory.h" #include "fake_display_information.h" #include "mock_brightness_control.h" #include "fake_client_requests.h" #include "fake_client_settings.h" #include "mock_display_power_control.h" #include "mock_display_power_event_sink.h" #include "fake_lid.h" #include "fake_log.h" #include "mock_modem_power_control.h" #include "fake_notification_service.h" #include "mock_performance_booster.h" #include "fake_power_button.h" #include "mock_power_button_event_sink.h" #include "fake_power_source.h" #include "fake_proximity_sensor.h" #include "fake_session_tracker.h" #include "fake_state_machine_options.h" #include "fake_system_power_control.h" #include "fake_timer.h" #include "fake_user_activity.h" #include "fake_voice_call_service.h" namespace rt = repowerd::test; using testing::NiceMock; using namespace std::chrono_literals; std::shared_ptr rt::DaemonConfig::the_display_information() { return the_fake_display_information(); } std::shared_ptr rt::DaemonConfig::the_brightness_control() { return the_mock_brightness_control(); } std::shared_ptr rt::DaemonConfig::the_client_requests() { return the_fake_client_requests(); } std::shared_ptr rt::DaemonConfig::the_client_settings() { return the_fake_client_settings(); } std::shared_ptr rt::DaemonConfig::the_display_power_control() { return the_mock_display_power_control(); } std::shared_ptr rt::DaemonConfig::the_display_power_event_sink() { return the_mock_display_power_event_sink(); } std::shared_ptr rt::DaemonConfig::the_lid() { return the_fake_lid(); } std::shared_ptr rt::DaemonConfig::the_log() { return the_fake_log(); } std::shared_ptr rt::DaemonConfig::the_modem_power_control() { return the_mock_modem_power_control(); } std::shared_ptr rt::DaemonConfig::the_notification_service() { return the_fake_notification_service(); } std::shared_ptr rt::DaemonConfig::the_performance_booster() { return the_mock_performance_booster(); } std::shared_ptr rt::DaemonConfig::the_power_button() { return the_fake_power_button(); } std::shared_ptr rt::DaemonConfig::the_power_button_event_sink() { return the_mock_power_button_event_sink(); } std::shared_ptr rt::DaemonConfig::the_power_source() { return the_fake_power_source(); } std::shared_ptr rt::DaemonConfig::the_proximity_sensor() { return the_fake_proximity_sensor(); } std::shared_ptr rt::DaemonConfig::the_session_tracker() { return the_fake_session_tracker(); } std::shared_ptr rt::DaemonConfig::the_state_machine_factory() { if (!state_machine_factory) state_machine_factory = std::make_shared(*this); return state_machine_factory; } std::shared_ptr rt::DaemonConfig::the_state_machine_options() { if (!state_machine_options) state_machine_options = std::make_shared(); return state_machine_options; } std::shared_ptr rt::DaemonConfig::the_system_power_control() { return the_fake_system_power_control(); } std::shared_ptr rt::DaemonConfig::the_timer() { return the_fake_timer(); } std::shared_ptr rt::DaemonConfig::the_user_activity() { return the_fake_user_activity(); } std::shared_ptr rt::DaemonConfig::the_voice_call_service() { return the_fake_voice_call_service(); } std::shared_ptr rt::DaemonConfig::the_fake_display_information() { if (!fake_display_information) fake_display_information = std::make_shared(); return fake_display_information; } std::shared_ptr> rt::DaemonConfig::the_mock_brightness_control() { if (!mock_brightness_control) mock_brightness_control = std::make_shared>(); return mock_brightness_control; } std::shared_ptr rt::DaemonConfig::the_fake_client_requests() { if (!fake_client_requests) fake_client_requests = std::make_shared(); return fake_client_requests; } std::shared_ptr rt::DaemonConfig::the_fake_client_settings() { if (!fake_client_settings) fake_client_settings = std::make_shared(); return fake_client_settings; } std::shared_ptr> rt::DaemonConfig::the_mock_display_power_control() { if (!mock_display_power_control) mock_display_power_control = std::make_shared>(); return mock_display_power_control; } std::shared_ptr> rt::DaemonConfig::the_mock_display_power_event_sink() { if (!mock_display_power_event_sink) mock_display_power_event_sink = std::make_shared>(); return mock_display_power_event_sink; } std::shared_ptr rt::DaemonConfig::the_fake_lid() { if (!fake_lid) fake_lid = std::make_shared(); return fake_lid; } std::shared_ptr rt::DaemonConfig::the_fake_log() { if (!fake_log) fake_log = std::make_shared(repowerd::LogLevel::Debug); return fake_log; } std::shared_ptr> rt::DaemonConfig::the_mock_modem_power_control() { if (!mock_modem_power_control) mock_modem_power_control = std::make_shared>(); return mock_modem_power_control; } std::shared_ptr rt::DaemonConfig::the_fake_notification_service() { if (!fake_notification_service) fake_notification_service = std::make_shared(); return fake_notification_service; } std::shared_ptr> rt::DaemonConfig::the_mock_performance_booster() { if (!mock_performance_booster) mock_performance_booster = std::make_shared>(); return mock_performance_booster; } std::shared_ptr rt::DaemonConfig::the_fake_power_button() { if (!fake_power_button) fake_power_button = std::make_shared(); return fake_power_button; } std::shared_ptr> rt::DaemonConfig::the_mock_power_button_event_sink() { if (!mock_power_button_event_sink) mock_power_button_event_sink = std::make_shared>(); return mock_power_button_event_sink; } std::shared_ptr rt::DaemonConfig::the_fake_power_source() { if (!fake_power_source) fake_power_source = std::make_shared(); return fake_power_source; } std::shared_ptr rt::DaemonConfig::the_fake_proximity_sensor() { if (!fake_proximity_sensor) fake_proximity_sensor = std::make_shared(); return fake_proximity_sensor; } std::shared_ptr rt::DaemonConfig::the_fake_session_tracker() { if (!fake_session_tracker) fake_session_tracker = std::make_shared(); return fake_session_tracker; } std::shared_ptr rt::DaemonConfig::the_fake_system_power_control() { if (!fake_system_power_control) fake_system_power_control = std::make_shared(); return fake_system_power_control; } std::shared_ptr rt::DaemonConfig::the_fake_timer() { if (!fake_timer) fake_timer = std::make_shared(); return fake_timer; } std::shared_ptr rt::DaemonConfig::the_fake_user_activity() { if (!fake_user_activity) fake_user_activity = std::make_shared(); return fake_user_activity; } std::shared_ptr rt::DaemonConfig::the_fake_voice_call_service() { if (!fake_voice_call_service) fake_voice_call_service = std::make_shared(); return fake_voice_call_service; } repowerd-2023.07/tests/core-tests/daemon_config.h000066400000000000000000000134721446034100200217120ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/daemon_config.h" #include namespace repowerd { namespace test { class FakeDisplayInformation; class MockBrightnessControl; class FakeClientRequests; class FakeClientSettings; class MockDisplayPowerControl; class MockDisplayPowerEventSink; class FakeLid; class FakeLog; class MockModemPowerControl; class FakeNotificationService; class MockPerformanceBooster; class FakePowerButton; class MockPowerButtonEventSink; class FakePowerSource; class FakeProximitySensor; class FakeSessionTracker; class FakeSystemPowerControl; class FakeTimer; class FakeUserActivity; class FakeVoiceCallService; class DaemonConfig : public repowerd::DaemonConfig { public: std::shared_ptr the_display_information() override; std::shared_ptr the_brightness_control() override; std::shared_ptr the_client_requests() override; std::shared_ptr the_client_settings() override; std::shared_ptr the_display_power_control() override; std::shared_ptr the_display_power_event_sink() override; std::shared_ptr the_lid() override; std::shared_ptr the_log() override; std::shared_ptr the_modem_power_control() override; std::shared_ptr the_notification_service() override; std::shared_ptr the_performance_booster() override; std::shared_ptr the_power_button() override; std::shared_ptr the_power_button_event_sink() override; std::shared_ptr the_power_source() override; std::shared_ptr the_proximity_sensor() override; std::shared_ptr the_session_tracker() override; std::shared_ptr the_state_machine_factory() override; std::shared_ptr the_state_machine_options() override; std::shared_ptr the_system_power_control() override; std::shared_ptr the_timer() override; std::shared_ptr the_user_activity() override; std::shared_ptr the_voice_call_service() override; std::shared_ptr the_fake_display_information(); std::shared_ptr> the_mock_brightness_control(); std::shared_ptr the_fake_client_requests(); std::shared_ptr the_fake_client_settings(); std::shared_ptr> the_mock_display_power_control(); std::shared_ptr> the_mock_display_power_event_sink(); std::shared_ptr the_fake_lid(); std::shared_ptr the_fake_log(); std::shared_ptr> the_mock_modem_power_control(); std::shared_ptr the_fake_notification_service(); std::shared_ptr> the_mock_performance_booster(); std::shared_ptr the_fake_power_button(); std::shared_ptr> the_mock_power_button_event_sink(); std::shared_ptr the_fake_power_source(); std::shared_ptr the_fake_proximity_sensor(); std::shared_ptr the_fake_session_tracker(); std::shared_ptr the_fake_system_power_control(); std::shared_ptr the_fake_timer(); std::shared_ptr the_fake_user_activity(); std::shared_ptr the_fake_voice_call_service(); private: std::shared_ptr state_machine_factory; std::shared_ptr state_machine_options; std::shared_ptr fake_display_information; std::shared_ptr> mock_brightness_control; std::shared_ptr fake_client_requests; std::shared_ptr fake_client_settings; std::shared_ptr> mock_display_power_control; std::shared_ptr> mock_display_power_event_sink; std::shared_ptr fake_lid; std::shared_ptr fake_log; std::shared_ptr> mock_modem_power_control; std::shared_ptr fake_notification_service; std::shared_ptr> mock_performance_booster; std::shared_ptr fake_power_button; std::shared_ptr> mock_power_button_event_sink; std::shared_ptr fake_power_source; std::shared_ptr fake_proximity_sensor; std::shared_ptr fake_session_tracker; std::shared_ptr fake_system_power_control; std::shared_ptr fake_timer; std::shared_ptr fake_user_activity; std::shared_ptr fake_voice_call_service; }; } } repowerd-2023.07/tests/core-tests/default_pid.h000066400000000000000000000014661446034100200214020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include namespace repowerd { namespace test { pid_t constexpr default_pid = 1000; } } repowerd-2023.07/tests/core-tests/fake_client_requests.cpp000066400000000000000000000135601446034100200236520ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_client_requests.h" namespace rt = repowerd::test; namespace { auto null_arg_handler = [](auto){}; auto null_arg2_handler = [](auto,auto){}; } rt::FakeClientRequests::FakeClientRequests() : disable_inactivity_timeout_handler{null_arg2_handler}, enable_inactivity_timeout_handler{null_arg2_handler}, set_inactivity_timeout_handler{null_arg2_handler}, disable_autobrightness_handler{null_arg_handler}, enable_autobrightness_handler{null_arg_handler}, set_normal_brightness_value_handler{null_arg2_handler} { } void rt::FakeClientRequests::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeClientRequests::register_disable_inactivity_timeout_handler( DisableInactivityTimeoutHandler const& handler) { mock.register_disable_inactivity_timeout_handler(handler); disable_inactivity_timeout_handler = handler; return HandlerRegistration{ [this] { mock.unregister_disable_inactivity_timeout_handler(); disable_inactivity_timeout_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_enable_inactivity_timeout_handler( EnableInactivityTimeoutHandler const& handler) { mock.register_enable_inactivity_timeout_handler(handler); enable_inactivity_timeout_handler = handler; return HandlerRegistration{ [this] { mock.unregister_enable_inactivity_timeout_handler(); enable_inactivity_timeout_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_set_inactivity_timeout_handler( SetInactivityTimeoutHandler const& handler) { mock.register_set_inactivity_timeout_handler(handler); set_inactivity_timeout_handler = handler; return HandlerRegistration{ [this] { mock.unregister_set_inactivity_timeout_handler(); set_inactivity_timeout_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_disable_autobrightness_handler( DisableAutobrightnessHandler const& handler) { mock.register_disable_autobrightness_handler(handler); disable_autobrightness_handler = handler; return HandlerRegistration{ [this] { mock.unregister_disable_autobrightness_handler(); disable_autobrightness_handler = null_arg_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_enable_autobrightness_handler( EnableAutobrightnessHandler const& handler) { mock.register_enable_autobrightness_handler(handler); enable_autobrightness_handler = handler; return HandlerRegistration{ [this] { mock.unregister_enable_autobrightness_handler(); enable_autobrightness_handler = null_arg_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_set_normal_brightness_value_handler( SetNormalBrightnessValueHandler const& handler) { mock.register_set_normal_brightness_value_handler(handler); set_normal_brightness_value_handler = handler; return HandlerRegistration{ [this] { mock.unregister_set_normal_brightness_value_handler(); set_normal_brightness_value_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_allow_suspend_handler( AllowSuspendHandler const& handler) { mock.register_allow_suspend_handler(handler); allow_suspend_handler = handler; return HandlerRegistration{ [this] { mock.unregister_allow_suspend_handler(); allow_suspend_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration rt::FakeClientRequests::register_disallow_suspend_handler( DisallowSuspendHandler const& handler) { mock.register_disallow_suspend_handler(handler); disallow_suspend_handler = handler; return HandlerRegistration{ [this] { mock.unregister_disallow_suspend_handler(); disallow_suspend_handler = null_arg2_handler; }}; } void rt::FakeClientRequests::emit_disable_inactivity_timeout( std::string const& id, pid_t pid) { disable_inactivity_timeout_handler(id, pid); } void rt::FakeClientRequests::emit_enable_inactivity_timeout( std::string const& id, pid_t pid) { enable_inactivity_timeout_handler(id, pid); } void rt::FakeClientRequests::emit_set_inactivity_timeout( std::chrono::milliseconds timeout, pid_t pid) { set_inactivity_timeout_handler(timeout, pid); } void rt::FakeClientRequests::emit_disable_autobrightness(pid_t pid) { disable_autobrightness_handler(pid); } void rt::FakeClientRequests::emit_enable_autobrightness(pid_t pid) { enable_autobrightness_handler(pid); } void rt::FakeClientRequests::emit_set_normal_brightness_value(double f, pid_t pid) { set_normal_brightness_value_handler(f, pid); } void rt::FakeClientRequests::emit_allow_suspend( std::string const& id, pid_t pid) { allow_suspend_handler(id, pid); } void rt::FakeClientRequests::emit_disallow_suspend( std::string const& id, pid_t pid) { disallow_suspend_handler(id, pid); } repowerd-2023.07/tests/core-tests/fake_client_requests.h000066400000000000000000000111041446034100200233070ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/client_requests.h" #include "default_pid.h" #include namespace repowerd { namespace test { class FakeClientRequests : public ClientRequests { public: FakeClientRequests(); void start_processing() override; HandlerRegistration register_disable_inactivity_timeout_handler( DisableInactivityTimeoutHandler const& handler) override; HandlerRegistration register_enable_inactivity_timeout_handler( EnableInactivityTimeoutHandler const& handler) override; HandlerRegistration register_set_inactivity_timeout_handler( SetInactivityTimeoutHandler const& handler) override; HandlerRegistration register_disable_autobrightness_handler( DisableAutobrightnessHandler const& handler) override; HandlerRegistration register_enable_autobrightness_handler( EnableAutobrightnessHandler const& handler) override; HandlerRegistration register_set_normal_brightness_value_handler( SetNormalBrightnessValueHandler const& handler) override; HandlerRegistration register_allow_suspend_handler( AllowSuspendHandler const& handler) override; HandlerRegistration register_disallow_suspend_handler( DisallowSuspendHandler const& handler) override; void emit_disable_inactivity_timeout(std::string const& id, pid_t pid = default_pid); void emit_enable_inactivity_timeout(std::string const& id, pid_t pid = default_pid); void emit_set_inactivity_timeout(std::chrono::milliseconds timeout, pid_t pid = default_pid); void emit_disable_autobrightness(pid_t pid = default_pid); void emit_enable_autobrightness(pid_t pid = default_pid); void emit_set_normal_brightness_value(double f, pid_t pid = default_pid); void emit_allow_suspend(std::string const& id, pid_t pid = default_pid); void emit_disallow_suspend(std::string const& id, pid_t pid = default_pid); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_disable_inactivity_timeout_handler, void(DisableInactivityTimeoutHandler const&)); MOCK_METHOD0(unregister_disable_inactivity_timeout_handler, void()); MOCK_METHOD1(register_enable_inactivity_timeout_handler, void(EnableInactivityTimeoutHandler const&)); MOCK_METHOD0(unregister_enable_inactivity_timeout_handler, void()); MOCK_METHOD1(register_set_inactivity_timeout_handler, void(SetInactivityTimeoutHandler const&)); MOCK_METHOD0(unregister_set_inactivity_timeout_handler, void()); MOCK_METHOD1(register_disable_autobrightness_handler, void(DisableAutobrightnessHandler const&)); MOCK_METHOD0(unregister_disable_autobrightness_handler, void()); MOCK_METHOD1(register_enable_autobrightness_handler, void(EnableAutobrightnessHandler const&)); MOCK_METHOD0(unregister_enable_autobrightness_handler, void()); MOCK_METHOD1(register_set_normal_brightness_value_handler, void(SetNormalBrightnessValueHandler const&)); MOCK_METHOD0(unregister_set_normal_brightness_value_handler, void()); MOCK_METHOD1(register_allow_suspend_handler, void(AllowSuspendHandler const&)); MOCK_METHOD0(unregister_allow_suspend_handler, void()); MOCK_METHOD1(register_disallow_suspend_handler, void(DisallowSuspendHandler const&)); MOCK_METHOD0(unregister_disallow_suspend_handler, void()); }; testing::NiceMock mock; private: DisableInactivityTimeoutHandler disable_inactivity_timeout_handler; EnableInactivityTimeoutHandler enable_inactivity_timeout_handler; SetInactivityTimeoutHandler set_inactivity_timeout_handler; DisableAutobrightnessHandler disable_autobrightness_handler; EnableAutobrightnessHandler enable_autobrightness_handler; SetNormalBrightnessValueHandler set_normal_brightness_value_handler; AllowSuspendHandler allow_suspend_handler; DisallowSuspendHandler disallow_suspend_handler; }; } } repowerd-2023.07/tests/core-tests/fake_client_settings.cpp000066400000000000000000000061741446034100200236420ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_client_settings.h" namespace rt = repowerd::test; namespace { auto null_arg2_handler = [](auto,auto){}; auto null_arg3_handler = [](auto,auto,auto){}; auto null_arg4_handler = [](auto,auto,auto,auto){}; } rt::FakeClientSettings::FakeClientSettings() : set_inactivity_behavior_handler{null_arg4_handler}, set_lid_behavior_handler{null_arg3_handler}, set_critical_power_behavior_handler{null_arg2_handler} { } void rt::FakeClientSettings::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeClientSettings::register_set_inactivity_behavior_handler( SetInactivityBehaviorHandler const& handler) { mock.register_set_inactivity_behavior_handler(handler); set_inactivity_behavior_handler = handler; return HandlerRegistration{ [this] { mock.unregister_set_inactivity_behavior_handler(); set_inactivity_behavior_handler = null_arg4_handler; }}; } repowerd::HandlerRegistration rt::FakeClientSettings::register_set_lid_behavior_handler( SetLidBehaviorHandler const& handler) { mock.register_set_lid_behavior_handler(handler); set_lid_behavior_handler = handler; return HandlerRegistration{ [this] { mock.unregister_set_lid_behavior_handler(); set_lid_behavior_handler = null_arg3_handler; }}; } repowerd::HandlerRegistration rt::FakeClientSettings::register_set_critical_power_behavior_handler( SetCriticalPowerBehaviorHandler const& handler) { mock.register_set_critical_power_behavior_handler(handler); set_critical_power_behavior_handler = handler; return HandlerRegistration{ [this] { mock.unregister_set_critical_power_behavior_handler(); set_critical_power_behavior_handler = null_arg2_handler; }}; } void rt::FakeClientSettings::emit_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid) { set_inactivity_behavior_handler(power_action, power_supply, timeout, pid); } void rt::FakeClientSettings::emit_set_lid_behavior( PowerAction power_action, PowerSupply power_supply, pid_t pid) { set_lid_behavior_handler(power_action, power_supply, pid); } void rt::FakeClientSettings::emit_set_critical_power_behavior( PowerAction power_action, pid_t pid) { set_critical_power_behavior_handler(power_action, pid); } repowerd-2023.07/tests/core-tests/fake_client_settings.h000066400000000000000000000052131446034100200233000ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/client_settings.h" #include "default_pid.h" #include namespace repowerd { namespace test { class FakeClientSettings : public ClientSettings { public: FakeClientSettings(); void start_processing() override; HandlerRegistration register_set_inactivity_behavior_handler( SetInactivityBehaviorHandler const& handler) override; HandlerRegistration register_set_lid_behavior_handler( SetLidBehaviorHandler const& handler) override; HandlerRegistration register_set_critical_power_behavior_handler( SetCriticalPowerBehaviorHandler const& handler) override; void emit_set_inactivity_behavior( PowerAction power_action, PowerSupply power_supply, std::chrono::milliseconds timeout, pid_t pid = default_pid); void emit_set_lid_behavior( PowerAction power_action, PowerSupply power_supply, pid_t pid = default_pid); void emit_set_critical_power_behavior( PowerAction power_action, pid_t pid = default_pid); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_set_inactivity_behavior_handler, void(SetInactivityBehaviorHandler const&)); MOCK_METHOD0(unregister_set_inactivity_behavior_handler, void()); MOCK_METHOD1(register_set_lid_behavior_handler, void(SetLidBehaviorHandler const&)); MOCK_METHOD0(unregister_set_lid_behavior_handler, void()); MOCK_METHOD1(register_set_critical_power_behavior_handler, void(SetCriticalPowerBehaviorHandler const&)); MOCK_METHOD0(unregister_set_critical_power_behavior_handler, void()); }; testing::NiceMock mock; private: SetInactivityBehaviorHandler set_inactivity_behavior_handler; SetLidBehaviorHandler set_lid_behavior_handler; SetCriticalPowerBehaviorHandler set_critical_power_behavior_handler; }; } } repowerd-2023.07/tests/core-tests/fake_display_information.cpp000066400000000000000000000021201446034100200245010ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_display_information.h" namespace rt = repowerd::test; rt::FakeDisplayInformation::FakeDisplayInformation() : has_active_external_displays_{false} { } bool rt::FakeDisplayInformation::has_active_external_displays() { return has_active_external_displays_; } void rt::FakeDisplayInformation::set_has_active_external_displays(bool b) { has_active_external_displays_ = b; } repowerd-2023.07/tests/core-tests/fake_display_information.h000066400000000000000000000021021446034100200241460ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/display_information.h" #include namespace repowerd { namespace test { class FakeDisplayInformation : public DisplayInformation { public: FakeDisplayInformation(); bool has_active_external_displays() override; void set_has_active_external_displays(bool b); private: std::atomic has_active_external_displays_; }; } } repowerd-2023.07/tests/core-tests/fake_lid.cpp000066400000000000000000000025021446034100200212030ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_lid.h" namespace rt = repowerd::test; rt::FakeLid::FakeLid() : lid_handler{[](auto){}} { } void rt::FakeLid::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeLid::register_lid_handler( LidHandler const& handler) { mock.register_lid_handler(handler); this->lid_handler = handler; return HandlerRegistration{ [this] { mock.unregister_lid_handler(); this->lid_handler = [](auto){}; }}; } void rt::FakeLid::close() { lid_handler(LidState::closed); } void rt::FakeLid::open() { lid_handler(LidState::open); } repowerd-2023.07/tests/core-tests/fake_lid.h000066400000000000000000000024361446034100200206560ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/lid.h" #include namespace repowerd { namespace test { class FakeLid : public Lid { public: FakeLid(); void start_processing() override; HandlerRegistration register_lid_handler( LidHandler const& handler) override; void close(); void open(); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_lid_handler, void(LidHandler const&)); MOCK_METHOD0(unregister_lid_handler, void()); }; testing::NiceMock mock; private: LidHandler lid_handler; }; } } repowerd-2023.07/tests/core-tests/fake_notification_service.cpp000066400000000000000000000040351446034100200246440ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_notification_service.h" namespace rt = repowerd::test; rt::FakeNotificationService::FakeNotificationService() : notification_handler{[](auto, auto){}}, notification_done_handler{[](auto, auto){}} { } void rt::FakeNotificationService::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeNotificationService::register_notification_handler( NotificationHandler const& handler) { mock.register_notification_handler(handler); notification_handler = handler; return HandlerRegistration{ [this] { mock.unregister_notification_handler(); notification_handler = [](auto, auto){}; }}; } void rt::FakeNotificationService::emit_notification(std::string const& id) { notification_handler(id, 1000); } repowerd::HandlerRegistration rt::FakeNotificationService::register_notification_done_handler( NotificationDoneHandler const& handler) { mock.register_notification_done_handler(handler); notification_done_handler = handler; return HandlerRegistration{ [this] { mock.unregister_notification_done_handler(); notification_done_handler = [](auto, auto){}; }}; } void rt::FakeNotificationService::emit_notification_done(std::string const& id) { notification_done_handler(id, 1000); } repowerd-2023.07/tests/core-tests/fake_notification_service.h000066400000000000000000000035141446034100200243120ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/notification_service.h" #include namespace repowerd { namespace test { class FakeNotificationService : public NotificationService { public: FakeNotificationService(); void start_processing() override; HandlerRegistration register_notification_handler( NotificationHandler const& handler) override; HandlerRegistration register_notification_done_handler( NotificationDoneHandler const& handler) override; void emit_notification(std::string const& id); void emit_notification_done(std::string const& id); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_notification_handler, void(NotificationHandler const&)); MOCK_METHOD0(unregister_notification_handler, void()); MOCK_METHOD1(register_notification_done_handler, void(NotificationDoneHandler const&)); MOCK_METHOD0(unregister_notification_done_handler, void()); }; testing::NiceMock mock; private: NotificationHandler notification_handler; NotificationDoneHandler notification_done_handler; }; } } repowerd-2023.07/tests/core-tests/fake_power_button.cpp000066400000000000000000000025501446034100200231650ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_power_button.h" namespace rt = repowerd::test; void rt::FakePowerButton::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakePowerButton::register_power_button_handler( PowerButtonHandler const& handler) { mock.register_power_button_handler(handler); this->handler = handler; return HandlerRegistration{ [this] { mock.unregister_power_button_handler(); this->handler = [](PowerButtonState){}; }}; } void rt::FakePowerButton::press() { handler(PowerButtonState::pressed); } void rt::FakePowerButton::release() { handler(PowerButtonState::released); } repowerd-2023.07/tests/core-tests/fake_power_button.h000066400000000000000000000025201446034100200226270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/power_button.h" #include namespace repowerd { namespace test { class FakePowerButton : public PowerButton { public: void start_processing() override; HandlerRegistration register_power_button_handler(PowerButtonHandler const& handler) override; void press(); void release(); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_power_button_handler, void(PowerButtonHandler const&)); MOCK_METHOD0(unregister_power_button_handler, void()); }; testing::NiceMock mock; private: PowerButtonHandler handler; }; } } repowerd-2023.07/tests/core-tests/fake_power_source.cpp000066400000000000000000000040511446034100200231500ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_power_source.h" namespace rt = repowerd::test; void rt::FakePowerSource::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakePowerSource::register_power_source_change_handler( PowerSourceChangeHandler const& handler) { mock.register_power_source_change_handler(handler); this->power_source_change_handler = handler; return HandlerRegistration{ [this] { mock.unregister_power_source_change_handler(); this->power_source_change_handler = []{}; }}; } repowerd::HandlerRegistration rt::FakePowerSource::register_power_source_critical_handler( PowerSourceChangeHandler const& handler) { mock.register_power_source_critical_handler(handler); this->power_source_critical_handler = handler; return HandlerRegistration{ [this] { mock.unregister_power_source_critical_handler(); this->power_source_critical_handler = []{}; }}; } bool rt::FakePowerSource::is_using_battery_power() { return is_using_battery_power_; } void rt::FakePowerSource::emit_power_source_change() { power_source_change_handler(); } void rt::FakePowerSource::emit_power_source_critical() { power_source_critical_handler(); } void rt::FakePowerSource::set_is_using_battery_power(bool b) { is_using_battery_power_ = b; } repowerd-2023.07/tests/core-tests/fake_power_source.h000066400000000000000000000036431446034100200226230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/power_source.h" #include namespace repowerd { namespace test { class FakePowerSource : public PowerSource { public: void start_processing() override; HandlerRegistration register_power_source_change_handler( PowerSourceChangeHandler const& handler) override; HandlerRegistration register_power_source_critical_handler( PowerSourceChangeHandler const& handler) override; bool is_using_battery_power() override; void emit_power_source_change(); void emit_power_source_critical(); void set_is_using_battery_power(bool b); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_power_source_change_handler, void(PowerSourceChangeHandler const&)); MOCK_METHOD0(unregister_power_source_change_handler, void()); MOCK_METHOD1(register_power_source_critical_handler, void(PowerSourceChangeHandler const&)); MOCK_METHOD0(unregister_power_source_critical_handler, void()); }; testing::NiceMock mock; private: PowerSourceChangeHandler power_source_change_handler; PowerSourceCriticalHandler power_source_critical_handler; bool is_using_battery_power_{true}; }; } } repowerd-2023.07/tests/core-tests/fake_proximity_sensor.cpp000066400000000000000000000037671446034100200241060ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_proximity_sensor.h" namespace rt = repowerd::test; rt::FakeProximitySensor::FakeProximitySensor() : events_enabled{false}, handler{[](ProximityState){}}, state{ProximityState::far} { } repowerd::HandlerRegistration rt::FakeProximitySensor::register_proximity_handler( ProximityHandler const& handler) { mock.register_proximity_handler(handler); this->handler = handler; return HandlerRegistration{ [this] { mock.unregister_proximity_handler(); this->handler = [](ProximityState){}; }}; } repowerd::ProximityState rt::FakeProximitySensor::proximity_state() { return state; } void rt::FakeProximitySensor::enable_proximity_events() { events_enabled = true; } void rt::FakeProximitySensor::disable_proximity_events() { events_enabled = false; } void rt::FakeProximitySensor::emit_proximity_state(ProximityState state) { this->state = state; handler(state); } void rt::FakeProximitySensor::emit_proximity_state_if_enabled(ProximityState state) { this->state = state; if (events_enabled) handler(state); } void rt::FakeProximitySensor::set_proximity_state(ProximityState state) { this->state = state; } bool rt::FakeProximitySensor::are_proximity_events_enabled() { return events_enabled; } repowerd-2023.07/tests/core-tests/fake_proximity_sensor.h000066400000000000000000000032051446034100200235360ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/proximity_sensor.h" #include namespace repowerd { namespace test { class FakeProximitySensor : public ProximitySensor { public: FakeProximitySensor(); HandlerRegistration register_proximity_handler( ProximityHandler const& handler) override; ProximityState proximity_state() override; void enable_proximity_events() override; void disable_proximity_events() override; void emit_proximity_state(ProximityState state); void emit_proximity_state_if_enabled(ProximityState state); void set_proximity_state(ProximityState state); bool are_proximity_events_enabled(); struct Mock { MOCK_METHOD1(register_proximity_handler, void(ProximityHandler const&)); MOCK_METHOD0(unregister_proximity_handler, void()); }; testing::NiceMock mock; private: bool events_enabled; ProximityHandler handler; ProximityState state; }; } } repowerd-2023.07/tests/core-tests/fake_session_tracker.cpp000066400000000000000000000060541446034100200236370ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_session_tracker.h" #include "default_pid.h" #include namespace rt = repowerd::test; namespace { auto const null_arg1_handler = [](auto){}; auto const null_arg2_handler = [](auto, auto){}; } rt::FakeSessionTracker::FakeSessionTracker() : active_session_changed_handler{null_arg2_handler}, session_removed_handler{null_arg1_handler} { } void rt::FakeSessionTracker::start_processing() { mock.start_processing(); add_session(default_session(), SessionType::RepowerdCompatible, default_pid); switch_to_session(default_session()); } repowerd::HandlerRegistration rt::FakeSessionTracker::register_active_session_changed_handler( ActiveSessionChangedHandler const& handler) { mock.register_active_session_changed_handler(handler); this->active_session_changed_handler = handler; return HandlerRegistration{ [this] { mock.unregister_active_session_changed_handler(); this->active_session_changed_handler = null_arg2_handler; }}; } repowerd::HandlerRegistration rt::FakeSessionTracker::register_session_removed_handler( SessionRemovedHandler const& handler) { mock.register_session_removed_handler(handler); this->session_removed_handler = handler; return HandlerRegistration{ [this] { mock.unregister_session_removed_handler(); this->session_removed_handler = null_arg1_handler; }}; } std::string rt::FakeSessionTracker::session_for_pid(pid_t pid) { auto const result = std::find_if(sessions.begin(), sessions.end(), [pid] (auto const& kv) { return kv.second.pid == pid; }); return result != sessions.end() ? result->first : std::string{}; } void rt::FakeSessionTracker::add_session( std::string const& session_id, SessionType type, pid_t pid) { sessions[session_id] = {type, pid}; } void rt::FakeSessionTracker::remove_session(std::string const& session_id) { if (sessions.erase(session_id) > 0) session_removed_handler(session_id); } void rt::FakeSessionTracker::switch_to_session(std::string const& session_id) { auto const iter = sessions.find(session_id); if (iter != sessions.end()) active_session_changed_handler(session_id, iter->second.type); } std::string rt::FakeSessionTracker::default_session() { return "InitialCompatibleSession"; } repowerd-2023.07/tests/core-tests/fake_session_tracker.h000066400000000000000000000043201446034100200232760ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/session_tracker.h" #include #include namespace repowerd { namespace test { class FakeSessionTracker : public SessionTracker { public: FakeSessionTracker(); void start_processing() override; HandlerRegistration register_active_session_changed_handler( ActiveSessionChangedHandler const& handler) override; HandlerRegistration register_session_removed_handler( SessionRemovedHandler const& handler) override; std::string session_for_pid(pid_t) override; void add_session(std::string const& session, SessionType type, pid_t pid); void remove_session(std::string const& session); void switch_to_session(std::string const& session_id); std::string default_session(); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_active_session_changed_handler, void(ActiveSessionChangedHandler const&)); MOCK_METHOD0(unregister_active_session_changed_handler, void()); MOCK_METHOD1(register_session_removed_handler, void(SessionRemovedHandler const&)); MOCK_METHOD0(unregister_session_removed_handler, void()); }; testing::NiceMock mock; private: ActiveSessionChangedHandler active_session_changed_handler; SessionRemovedHandler session_removed_handler; struct SessionInfo { SessionType type; pid_t pid; }; std::unordered_map sessions; }; } } repowerd-2023.07/tests/core-tests/fake_state_machine_options.cpp000066400000000000000000000036011446034100200250130ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_state_machine_options.h" #include "src/core/infinite_timeout.h" using namespace std::chrono_literals; namespace rt = repowerd::test; std::chrono::milliseconds rt::FakeStateMachineOptions::notification_expiration_timeout() const { return 60s; } std::chrono::milliseconds rt::FakeStateMachineOptions::power_button_long_press_timeout() const { return 2s; } std::chrono::milliseconds rt::FakeStateMachineOptions::user_inactivity_normal_display_dim_duration() const { return 10s; } std::chrono::milliseconds rt::FakeStateMachineOptions::user_inactivity_normal_display_off_timeout() const { return 60s; } std::chrono::milliseconds rt::FakeStateMachineOptions::user_inactivity_normal_suspend_timeout() const { return 120s; } std::chrono::milliseconds rt::FakeStateMachineOptions::user_inactivity_post_notification_display_off_timeout() const { return 5s; } std::chrono::milliseconds rt::FakeStateMachineOptions::user_inactivity_reduced_display_off_timeout() const { return 10s; } bool rt::FakeStateMachineOptions::treat_power_button_as_user_activity() const { return false; } bool rt::FakeStateMachineOptions::turn_on_display_at_startup() const { return false; } repowerd-2023.07/tests/core-tests/fake_state_machine_options.h000066400000000000000000000031251446034100200244610ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/state_machine_options.h" namespace repowerd { namespace test { class FakeStateMachineOptions : public StateMachineOptions { public: std::chrono::milliseconds notification_expiration_timeout() const override; std::chrono::milliseconds power_button_long_press_timeout() const override; std::chrono::milliseconds user_inactivity_normal_display_dim_duration() const override; std::chrono::milliseconds user_inactivity_normal_display_off_timeout() const override; std::chrono::milliseconds user_inactivity_normal_suspend_timeout() const override; std::chrono::milliseconds user_inactivity_post_notification_display_off_timeout() const override; std::chrono::milliseconds user_inactivity_reduced_display_off_timeout() const override; bool treat_power_button_as_user_activity() const override; bool turn_on_display_at_startup() const override; }; } } repowerd-2023.07/tests/core-tests/fake_timer.cpp000066400000000000000000000052001446034100200215510ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_timer.h" #include namespace rt = repowerd::test; rt::FakeTimer::FakeTimer() : handler{[](AlarmId){}}, next_alarm_id{1}, now_ms{0} { } repowerd::HandlerRegistration rt::FakeTimer::register_alarm_handler(AlarmHandler const& handler) { mock.register_alarm_handler(handler); std::lock_guard lock{mutex}; this->handler = handler; return HandlerRegistration{ [this] { mock.unregister_alarm_handler(); std::lock_guard lock{mutex}; this->handler = [](AlarmId){}; }}; } repowerd::AlarmId rt::FakeTimer::schedule_alarm_in(std::chrono::milliseconds t) { std::lock_guard lock{mutex}; alarms.push_back({next_alarm_id, now_ms + t}); return next_alarm_id++; } void rt::FakeTimer::cancel_alarm(AlarmId id) { std::lock_guard lock{mutex}; alarms.erase( std::remove_if( alarms.begin(), alarms.end(), [id](auto const& alarm) { return alarm.id == id; }), alarms.end()); } std::chrono::steady_clock::time_point rt::FakeTimer::now() { std::lock_guard lock{mutex}; return std::chrono::steady_clock::time_point{now_ms}; } void rt::FakeTimer::advance_by(std::chrono::milliseconds advance) { // It's not ideal to call the handlers under lock, but it's good/safe // enough for our testing scenarios and purposes. The only timer // handler we use in production code (in repowerd::Daemon) enqueues // work to other threads, so it can't deadlock. std::lock_guard lock{mutex}; now_ms += advance; for (auto const& alarm : alarms) { if (now_ms >= alarm.time) handler(alarm.id); } alarms.erase( std::remove_if( alarms.begin(), alarms.end(), [this](auto const& alarm) { return now_ms >= alarm.time; }), alarms.end()); } repowerd-2023.07/tests/core-tests/fake_timer.h000066400000000000000000000032041446034100200212200ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/timer.h" #include #include #include namespace repowerd { namespace test { class FakeTimer : public Timer { public: FakeTimer(); HandlerRegistration register_alarm_handler(AlarmHandler const& handler) override; AlarmId schedule_alarm_in(std::chrono::milliseconds t) override; void cancel_alarm(AlarmId id) override; std::chrono::steady_clock::time_point now() override; void advance_by(std::chrono::milliseconds advance); struct Mock { MOCK_METHOD1(register_alarm_handler, void(AlarmHandler const&)); MOCK_METHOD0(unregister_alarm_handler, void()); }; testing::NiceMock mock; private: struct Alarm { AlarmId id; std::chrono::milliseconds time; }; std::mutex mutex; AlarmHandler handler; AlarmId next_alarm_id; std::chrono::milliseconds now_ms; std::vector alarms; }; } } repowerd-2023.07/tests/core-tests/fake_user_activity.cpp000066400000000000000000000025641446034100200233350ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_user_activity.h" namespace rt = repowerd::test; rt::FakeUserActivity::FakeUserActivity() : handler{[](UserActivityType){}} { } void rt::FakeUserActivity::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeUserActivity::register_user_activity_handler( UserActivityHandler const& handler) { mock.register_user_activity_handler(handler); this->handler = handler; return HandlerRegistration{ [this] { mock.unregister_user_activity_handler(); this->handler = [](UserActivityType){}; }}; } void rt::FakeUserActivity::perform(UserActivityType type) { handler(type); } repowerd-2023.07/tests/core-tests/fake_user_activity.h000066400000000000000000000025761446034100200230050ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/user_activity.h" #include namespace repowerd { namespace test { class FakeUserActivity : public UserActivity { public: FakeUserActivity(); void start_processing() override; HandlerRegistration register_user_activity_handler( UserActivityHandler const& handler) override; void perform(UserActivityType type); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_user_activity_handler, void(UserActivityHandler const&)); MOCK_METHOD0(unregister_user_activity_handler, void()); }; testing::NiceMock mock; private: UserActivityHandler handler; }; } } repowerd-2023.07/tests/core-tests/fake_voice_call_service.cpp000066400000000000000000000035661446034100200242660ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_voice_call_service.h" namespace rt = repowerd::test; rt::FakeVoiceCallService::FakeVoiceCallService() : active_call_handler{[]{}}, no_active_call_handler{[]{}} { } void rt::FakeVoiceCallService::start_processing() { mock.start_processing(); } repowerd::HandlerRegistration rt::FakeVoiceCallService::register_active_call_handler( ActiveCallHandler const& handler) { mock.register_active_call_handler(handler); active_call_handler = handler; return HandlerRegistration{ [this] { mock.unregister_active_call_handler(); active_call_handler = []{}; }}; } void rt::FakeVoiceCallService::emit_active_call() { active_call_handler(); } repowerd::HandlerRegistration rt::FakeVoiceCallService::register_no_active_call_handler( NoActiveCallHandler const& handler) { mock.register_no_active_call_handler(handler); no_active_call_handler = handler; return HandlerRegistration{ [this] { mock.unregister_no_active_call_handler(); no_active_call_handler = []{}; }}; } void rt::FakeVoiceCallService::emit_no_active_call() { no_active_call_handler(); } repowerd-2023.07/tests/core-tests/fake_voice_call_service.h000066400000000000000000000033341446034100200237240ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/voice_call_service.h" #include namespace repowerd { namespace test { class FakeVoiceCallService : public VoiceCallService { public: FakeVoiceCallService(); void start_processing() override; HandlerRegistration register_active_call_handler( ActiveCallHandler const& handler) override; HandlerRegistration register_no_active_call_handler( NoActiveCallHandler const& handler) override; void emit_active_call(); void emit_no_active_call(); struct Mock { MOCK_METHOD0(start_processing, void()); MOCK_METHOD1(register_active_call_handler, void(ActiveCallHandler const&)); MOCK_METHOD0(unregister_active_call_handler, void()); MOCK_METHOD1(register_no_active_call_handler, void(NoActiveCallHandler const&)); MOCK_METHOD0(unregister_no_active_call_handler, void()); }; testing::NiceMock mock; private: ActiveCallHandler active_call_handler; NoActiveCallHandler no_active_call_handler; }; } } repowerd-2023.07/tests/core-tests/mock_brightness_control.h000066400000000000000000000022571446034100200240420ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/brightness_control.h" #include namespace repowerd { namespace test { class MockBrightnessControl : public BrightnessControl { public: MOCK_METHOD0(disable_autobrightness, void()); MOCK_METHOD0(enable_autobrightness, void()); MOCK_METHOD0(set_dim_brightness, void()); MOCK_METHOD0(set_normal_brightness, void()); MOCK_METHOD1(set_normal_brightness_value, void(double)); MOCK_METHOD0(set_off_brightness, void()); }; } } repowerd-2023.07/tests/core-tests/mock_display_power_control.h000066400000000000000000000020021446034100200245370ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/display_power_control.h" #include namespace repowerd { namespace test { class MockDisplayPowerControl : public DisplayPowerControl { public: MOCK_METHOD1(turn_on, void(DisplayPowerControlFilter)); MOCK_METHOD1(turn_off, void(DisplayPowerControlFilter)); }; } } repowerd-2023.07/tests/core-tests/mock_display_power_event_sink.h000066400000000000000000000020471446034100200252350ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/display_power_event_sink.h" #include namespace repowerd { namespace test { class MockDisplayPowerEventSink : public DisplayPowerEventSink { public: MOCK_METHOD1(notify_display_power_off, void(DisplayPowerChangeReason)); MOCK_METHOD1(notify_display_power_on, void(DisplayPowerChangeReason)); }; } } repowerd-2023.07/tests/core-tests/mock_modem_power_control.h000066400000000000000000000017421446034100200242050ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/modem_power_control.h" #include namespace repowerd { namespace test { class MockModemPowerControl : public ModemPowerControl { public: MOCK_METHOD0(set_low_power_mode, void()); MOCK_METHOD0(set_normal_power_mode, void()); }; } } repowerd-2023.07/tests/core-tests/mock_performance_booster.h000066400000000000000000000017541446034100200241710ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/performance_booster.h" #include namespace repowerd { namespace test { class MockPerformanceBooster : public PerformanceBooster { public: MOCK_METHOD0(enable_interactive_mode, void()); MOCK_METHOD0(disable_interactive_mode, void()); }; } } repowerd-2023.07/tests/core-tests/mock_power_button_event_sink.h000066400000000000000000000016731446034100200251070ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #pragma once #include "src/core/power_button_event_sink.h" #include namespace repowerd { namespace test { class MockPowerButtonEventSink : public PowerButtonEventSink { public: MOCK_METHOD0(notify_long_press, void()); }; } } repowerd-2023.07/tests/core-tests/run_daemon.cpp000066400000000000000000000023021446034100200215720ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "run_daemon.h" #include "src/core/daemon.h" std::thread repowerd::test::run_daemon(Daemon& daemon) { auto daemon_thread = std::thread{[&] { daemon.run(); }}; // Flush twice to ensure the daemon has started up fully. The first flush // ensures the daemon has entered the main loop. The second flush ensures // that any startup events (e.g. from FakeSessionTracker to set the active // session) have been processed. daemon.flush(); daemon.flush(); return daemon_thread; } repowerd-2023.07/tests/core-tests/run_daemon.h000066400000000000000000000014661446034100200212510ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include namespace repowerd { class Daemon; namespace test { std::thread run_daemon(Daemon& daemon); } } repowerd-2023.07/tests/core-tests/test_client_requests.cpp000066400000000000000000000240451446034100200237230ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct AClientRequest : rt::AcceptanceTest { std::chrono::milliseconds const suspend_timeout{ user_inactivity_normal_suspend_timeout + 10s}; }; } TEST_F(AClientRequest, to_disable_inactivity_timeout_turns_on_display) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); } TEST_F(AClientRequest, to_disable_inactivity_timeout_brightens_display_if_already_on) { turn_on_display(); expect_display_brightens(); client_request_disable_inactivity_timeout(); } TEST_F(AClientRequest, to_disable_inactivity_timeout_works) { turn_on_display(); client_request_disable_inactivity_timeout(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(AClientRequest, to_disable_inactivity_timeout_does_not_affect_power_button) { turn_on_display(); client_request_disable_inactivity_timeout(); expect_display_turns_off(); press_power_button(); release_power_button(); } TEST_F(AClientRequest, to_enable_inactivity_timeout_turns_off_display_after_normal_timeout_if_inactivity_timeout_has_expired) { turn_on_display(); expect_no_display_power_change(); client_request_disable_inactivity_timeout(); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_no_display_power_change(); client_request_enable_inactivity_timeout(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AClientRequest, to_enable_inactivity_timeout_turns_off_display_extends_existing_inactivity_timeout) { turn_on_display(); expect_no_display_power_change(); client_request_disable_inactivity_timeout(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); client_request_enable_inactivity_timeout(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AClientRequest, to_set_inactivity_timeout_affects_display_off_timeout) { auto const display_off_timeout = user_inactivity_normal_display_off_timeout + 10s; client_request_set_inactivity_timeout(display_off_timeout); turn_on_display(); expect_no_display_power_change(); advance_time_by(display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AClientRequest, to_set_inactivity_timeout_affects_display_dim_timeout) { auto const display_off_timeout = user_inactivity_normal_display_off_timeout + 10s; auto const display_dim_timeout = display_off_timeout - user_inactivity_normal_display_dim_duration; client_request_set_inactivity_timeout(display_off_timeout); turn_on_display(); expect_no_display_brightness_change(); advance_time_by(display_dim_timeout - 1ms); verify_expectations(); expect_display_dims(); advance_time_by(1ms); } TEST_F(AClientRequest, to_set_short_inactivity_timeout_cancels_display_dim_timeout) { auto const display_off_timeout = user_inactivity_normal_display_dim_duration; client_request_set_inactivity_timeout(display_off_timeout); turn_on_display(); expect_no_display_brightness_change(); advance_time_by(display_off_timeout - 1ms); } TEST_F(AClientRequest, to_set_infinite_inactivity_timeout_keeps_screen_on_forever_if_turned_on_by_power_button) { turn_on_display(); client_request_set_inactivity_timeout(infinite_timeout); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(1h); } TEST_F(AClientRequest, to_set_infinite_inactivity_timeout_keeps_screen_on_forever_after_user_activity) { expect_display_turns_on(); emit_notification(); emit_notification_done(); verify_expectations(); perform_user_activity_extending_power_state(); client_request_set_inactivity_timeout(infinite_timeout); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(1h); } TEST_F(AClientRequest, to_set_infinite_inactivity_allows_power_button_to_turn_off_screen) { turn_on_display(); client_request_set_inactivity_timeout(infinite_timeout); turn_off_display(); } TEST_F(AClientRequest, to_set_non_positive_inactivity_timeout_is_ignrored) { client_request_set_inactivity_timeout(-1ms); client_request_set_inactivity_timeout(0ms); turn_on_display(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AClientRequest, to_disable_inactivity_timeout_works_until_all_requests_are_removed) { std::string const inactivity_id1{"1"}; std::string const inactivity_id2{"2"}; std::string const inactivity_id3{"3"}; expect_display_turns_on(); client_request_disable_inactivity_timeout(inactivity_id1); verify_expectations(); expect_display_brightens(); client_request_disable_inactivity_timeout(inactivity_id2); verify_expectations(); expect_display_brightens(); client_request_disable_inactivity_timeout(inactivity_id3); verify_expectations(); expect_no_display_power_change(); client_request_enable_inactivity_timeout(inactivity_id1); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_no_display_power_change(); client_request_enable_inactivity_timeout(inactivity_id2); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_display_turns_off(); client_request_enable_inactivity_timeout(inactivity_id3); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); } TEST_F(AClientRequest, to_enable_autobrightness_works) { expect_autobrightness_enabled(); client_request_enable_autobrightness(); } TEST_F(AClientRequest, to_disable_autobrightness_works) { expect_autobrightness_disabled(); client_request_disable_autobrightness(); } TEST_F(AClientRequest, to_set_brightness_value_works) { expect_normal_brightness_value_set_to(0.56); client_request_set_normal_brightness_value(0.56); } TEST_F(AClientRequest, to_disallow_suspend_works) { turn_on_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, repowerd::PowerSupply::battery, suspend_timeout); client_request_disallow_suspend(); expect_display_turns_off(); expect_no_system_power_change(); advance_time_by(suspend_timeout); } TEST_F(AClientRequest, to_allow_suspend_suspends_immediately_if_timeout_expired) { turn_on_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, repowerd::PowerSupply::battery, suspend_timeout); client_request_disallow_suspend(); expect_display_turns_off(); expect_no_system_power_change(); advance_time_by(suspend_timeout); verify_expectations(); expect_system_suspends(); client_request_allow_suspend(); } TEST_F(AClientRequest, to_allow_suspend_does_not_suspend_immediately_if_timeout_not_expired) { turn_on_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, repowerd::PowerSupply::battery, suspend_timeout); client_request_disallow_suspend(); expect_display_turns_off(); advance_time_by(user_inactivity_normal_suspend_timeout); verify_expectations(); expect_no_system_power_change(); client_request_allow_suspend(); verify_expectations(); expect_system_suspends(); advance_time_by(10s); } TEST_F(AClientRequest, to_disable_inactivity_timeout_is_logged) { client_request_disable_inactivity_timeout(); EXPECT_TRUE(log_contains_line({"disable_inactivity_timeout"})); } TEST_F(AClientRequest, to_enable_inactivity_timeout_is_logged) { client_request_enable_inactivity_timeout(); EXPECT_TRUE(log_contains_line({"enable_inactivity_timeout"})); } TEST_F(AClientRequest, to_set_inactivity_timeout_is_logged) { client_request_set_inactivity_timeout(15000ms); EXPECT_TRUE(log_contains_line({"set_inactivity_behavior", "display_off", "battery", "15000"})); EXPECT_TRUE(log_contains_line({"set_inactivity_behavior", "display_off", "line_power", "15000"})); } TEST_F(AClientRequest, to_disable_autobrightness_is_logged) { client_request_disable_autobrightness(); EXPECT_TRUE(log_contains_line({"disable_autobrightness"})); } TEST_F(AClientRequest, to_enable_autobrightness_is_logged) { client_request_enable_autobrightness(); EXPECT_TRUE(log_contains_line({"enable_autobrightness"})); } TEST_F(AClientRequest, to_set_normal_brightness_value_is_logged) { client_request_set_normal_brightness_value(0.67); EXPECT_TRUE(log_contains_line({"set_normal_brightness_value", "0.67"})); } TEST_F(AClientRequest, to_allow_suspend_is_logged) { client_request_allow_suspend(); EXPECT_TRUE(log_contains_line({"allow_suspend"})); } TEST_F(AClientRequest, to_disallow_suspend_is_logged) { client_request_disallow_suspend(); EXPECT_TRUE(log_contains_line({"disallow_suspend"})); } repowerd-2023.07/tests/core-tests/test_client_settings.cpp000066400000000000000000000374101446034100200237100ustar00rootroot00000000000000/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "src/core/infinite_timeout.h" #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; using namespace testing; namespace { std::string power_supply_to_str(repowerd::PowerSupply power_supply) { if (power_supply == repowerd::PowerSupply::battery) return "battery"; else if (power_supply == repowerd::PowerSupply::line_power) return "line_power"; return "unknown"; } repowerd::PowerSupply other(repowerd::PowerSupply power_supply) { if (power_supply == repowerd::PowerSupply::battery) return repowerd::PowerSupply::line_power; else if (power_supply == repowerd::PowerSupply::line_power) return repowerd::PowerSupply::battery; throw std::runtime_error("Invalid power_supply value"); } struct AClientSetting : rt::AcceptanceTest, WithParamInterface { AClientSetting() : display_off_timeout{user_inactivity_normal_display_off_timeout + 10s}, suspend_timeout{user_inactivity_normal_suspend_timeout + 10s}, power_supply{GetParam()} { } void apply_power_supply(repowerd::PowerSupply power_supply) { if (power_supply == repowerd::PowerSupply::battery) { use_battery_power(); emit_power_source_change(); } else if (power_supply == repowerd::PowerSupply::line_power) { use_line_power(); emit_power_source_change(); } } std::chrono::milliseconds const display_off_timeout; std::chrono::milliseconds const suspend_timeout; repowerd::PowerSupply const power_supply; }; } TEST_P(AClientSetting, for_display_off_timeout_is_used_on_matching_power_supply) { client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout); apply_power_supply(power_supply); turn_off_display(); turn_on_display(); expect_no_display_power_change(); advance_time_by(display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_timeout_is_not_used_on_non_matching_power_supply) { client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout); apply_power_supply(other(power_supply)); turn_off_display(); turn_on_display(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_timeout_reschedules_timeout_on_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); turn_on_display(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout); expect_no_display_power_change(); advance_time_by(display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_timeout_does_not_reschedule_timeout_on_non_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); turn_on_display(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, other(power_supply), display_off_timeout); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_timeout_is_used_when_switching_to_matching_power_supply) { apply_power_supply(other(power_supply)); turn_off_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout); turn_on_display(); advance_time_by(user_inactivity_normal_display_off_timeout - 20s); apply_power_supply(power_supply); expect_no_system_power_change(); advance_time_by(display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_timeout_is_used_when_performing_user_activity_after_switching_to_matching_power_supply) { apply_power_supply(other(power_supply)); turn_off_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout); turn_on_display(); advance_time_by(user_inactivity_normal_display_off_timeout - 20s); apply_power_supply(power_supply); perform_user_activity_extending_power_state(); expect_no_display_power_change(); advance_time_by(display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_timeout_is_used_on_matching_power_supply_when_session_starts) { auto const pid = rt::default_pid + 100; apply_power_supply(power_supply); turn_off_display(); add_compatible_session("c0", pid); switch_to_session("c0"); client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout, pid); turn_on_display(); expect_no_display_power_change(); advance_time_by(display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_P(AClientSetting, for_display_off_inactivity_behavior_is_logged) { client_setting_set_inactivity_behavior( repowerd::PowerAction::display_off, power_supply, display_off_timeout); auto const timeout_str = std::to_string(display_off_timeout.count()); EXPECT_TRUE( log_contains_line({ "set_inactivity_behavior", "display_off", power_supply_to_str(power_supply), timeout_str})); } TEST_P(AClientSetting, for_suspend_timeout_is_used_on_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, power_supply, suspend_timeout); turn_on_display(); expect_display_turns_off(); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_no_system_power_change(); advance_time_by( suspend_timeout - user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_system_suspends(); advance_time_by(1ms); } TEST_P(AClientSetting, for_infinite_suspend_timeout_disables_suspend_on_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, power_supply, repowerd::infinite_timeout); turn_on_display(); expect_display_turns_off(); expect_no_system_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_no_system_power_change(); advance_time_by(500h); verify_expectations(); } TEST_P(AClientSetting, for_infinite_suspend_timeout_is_used_when_changing_to_matching_power_supply) { apply_power_supply(other(power_supply)); turn_off_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, power_supply, repowerd::infinite_timeout); turn_on_display(); apply_power_supply(power_supply); expect_display_turns_off(); expect_no_system_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_no_system_power_change(); advance_time_by(500h); verify_expectations(); } TEST_P(AClientSetting, for_suspend_timeout_is_used_on_matching_power_supply_when_session_starts) { auto const pid = rt::default_pid + 100; apply_power_supply(power_supply); turn_off_display(); add_compatible_session("c0", pid); switch_to_session("c0"); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, power_supply, suspend_timeout, pid); turn_on_display(); expect_display_turns_off(); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_no_system_power_change(); advance_time_by( suspend_timeout - user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_system_suspends(); advance_time_by(1ms); } TEST_P(AClientSetting, for_unsupported_action_in_inactivity_behavior_is_ignored) { auto const timeout = 10s; apply_power_supply(power_supply); turn_off_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::none, power_supply, timeout); client_setting_set_inactivity_behavior( repowerd::PowerAction::power_off, power_supply, timeout); turn_on_display(); expect_no_system_power_change(); expect_no_display_power_change(); advance_time_by(timeout); } TEST_P(AClientSetting, for_suspend_inactivity_behavior_is_logged) { client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, power_supply, display_off_timeout); auto const timeout_str = std::to_string(display_off_timeout.count()); EXPECT_TRUE( log_contains_line({ "set_inactivity_behavior", "suspend", power_supply_to_str(power_supply), timeout_str})); } TEST_P(AClientSetting, for_suspend_lid_behavior_is_used_on_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_lid_behavior( repowerd::PowerAction::suspend, power_supply); turn_on_display(); expect_system_suspends(); close_lid(); } TEST_P(AClientSetting, for_suspend_lid_behavior_is_logged) { client_setting_set_lid_behavior( repowerd::PowerAction::suspend, power_supply); EXPECT_TRUE( log_contains_line({ "set_lid_behavior", "suspend", power_supply_to_str(power_supply)})); } TEST_P(AClientSetting, for_none_lid_behavior_is_used_on_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_lid_behavior( repowerd::PowerAction::none, power_supply); turn_on_display(); expect_no_system_power_change(); expect_display_turns_off(); close_lid(); } TEST_P(AClientSetting, for_none_lid_behavior_is_not_used_on_non_matching_power_supply) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_lid_behavior( repowerd::PowerAction::none, power_supply); apply_power_supply(other(power_supply)); turn_off_display(); turn_on_display(); expect_system_suspends(); close_lid(); } TEST_P(AClientSetting, for_none_lid_behavior_is_used_on_matching_power_supply_when_session_starts) { auto const pid = rt::default_pid + 100; apply_power_supply(power_supply); turn_off_display(); add_compatible_session("c0", pid); switch_to_session("c0"); client_setting_set_lid_behavior( repowerd::PowerAction::none, power_supply, pid); turn_on_display(); expect_no_system_power_change(); expect_display_turns_off(); close_lid(); } TEST_P(AClientSetting, for_none_lid_behavior_is_logged) { client_setting_set_lid_behavior( repowerd::PowerAction::none, power_supply); EXPECT_TRUE( log_contains_line({ "set_lid_behavior", "none", power_supply_to_str(power_supply)})); } TEST_P(AClientSetting, for_display_off_lid_behavior_is_ignored) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_lid_behavior( repowerd::PowerAction::suspend, power_supply); client_setting_set_lid_behavior( repowerd::PowerAction::display_off, power_supply); turn_on_display(); expect_system_suspends(); close_lid(); } TEST_P(AClientSetting, for_display_off_lid_behavior_is_logged) { client_setting_set_lid_behavior( repowerd::PowerAction::display_off, power_supply); EXPECT_TRUE( log_contains_line({ "set_lid_behavior", "display_off", power_supply_to_str(power_supply)})); } TEST_P(AClientSetting, for_power_off_lid_behavior_is_ignored) { apply_power_supply(power_supply); turn_off_display(); client_setting_set_lid_behavior( repowerd::PowerAction::none, power_supply); client_setting_set_lid_behavior( repowerd::PowerAction::power_off, power_supply); turn_on_display(); expect_no_system_power_change(); expect_display_turns_off(); close_lid(); } TEST_P(AClientSetting, for_power_off_lid_behavior_is_logged) { client_setting_set_lid_behavior( repowerd::PowerAction::power_off, power_supply); EXPECT_TRUE( log_contains_line({ "set_lid_behavior", "power_off", power_supply_to_str(power_supply)})); } TEST_P(AClientSetting, for_suspend_critical_power_behavior_is_used) { client_setting_set_critical_power_behavior(repowerd::PowerAction::suspend); expect_system_suspends(); emit_power_source_critical(); } TEST_P(AClientSetting, for_suspend_critical_power_behavior_is_logged) { client_setting_set_critical_power_behavior(repowerd::PowerAction::suspend); EXPECT_TRUE(log_contains_line({"set_critical_power_behavior", "suspend"})); } TEST_P(AClientSetting, for_power_off_critical_power_behavior_is_used) { client_setting_set_critical_power_behavior(repowerd::PowerAction::power_off); expect_system_powers_off(); emit_power_source_critical(); } TEST_P(AClientSetting, for_power_off_critical_power_behavior_is_logged) { client_setting_set_critical_power_behavior(repowerd::PowerAction::power_off); EXPECT_TRUE(log_contains_line({"set_critical_power_behavior", "power_off"})); } TEST_P(AClientSetting, for_none_critical_power_behavior_is_ignored) { client_setting_set_critical_power_behavior(repowerd::PowerAction::power_off); client_setting_set_critical_power_behavior(repowerd::PowerAction::none); expect_system_powers_off(); emit_power_source_critical(); } TEST_P(AClientSetting, for_display_off_critical_power_behavior_is_ignored) { client_setting_set_critical_power_behavior(repowerd::PowerAction::power_off); client_setting_set_critical_power_behavior(repowerd::PowerAction::display_off); expect_system_powers_off(); emit_power_source_critical(); } INSTANTIATE_TEST_CASE_P(WithPowerSupply, AClientSetting, Values( repowerd::PowerSupply::battery, repowerd::PowerSupply::line_power)); repowerd-2023.07/tests/core-tests/test_daemon.cpp000066400000000000000000001204221446034100200217510ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "daemon_config.h" #include "run_daemon.h" #include "fake_client_requests.h" #include "fake_client_settings.h" #include "fake_lid.h" #include "fake_notification_service.h" #include "fake_power_button.h" #include "fake_power_source.h" #include "fake_proximity_sensor.h" #include "fake_session_tracker.h" #include "fake_system_power_control.h" #include "fake_timer.h" #include "fake_user_activity.h" #include "fake_voice_call_service.h" #include "mock_brightness_control.h" #include "src/core/daemon.h" #include "src/core/state_machine.h" #include "src/core/state_machine_factory.h" #include #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct MockStateMachine : public repowerd::StateMachine { MockStateMachine( std::shared_ptr const& sessions_activity_log, std::string const& name) : sessions_activity_log{sessions_activity_log}, name{name} { } MOCK_METHOD1(handle_alarm, void(repowerd::AlarmId)); MOCK_METHOD0(handle_active_call, void()); MOCK_METHOD0(handle_no_active_call, void()); MOCK_METHOD0(handle_no_notification, void()); MOCK_METHOD0(handle_notification, void()); MOCK_METHOD0(handle_lid_closed, void()); MOCK_METHOD0(handle_lid_open, void()); MOCK_METHOD2(handle_set_lid_behavior, void(repowerd::PowerAction power_action, repowerd::PowerSupply power_supply)); MOCK_METHOD0(handle_power_button_press, void()); MOCK_METHOD0(handle_power_button_release, void()); MOCK_METHOD0(handle_power_source_change, void()); MOCK_METHOD0(handle_power_source_critical, void()); MOCK_METHOD1(handle_set_critical_power_behavior, void(repowerd::PowerAction power_action)); MOCK_METHOD0(handle_proximity_far, void()); MOCK_METHOD0(handle_proximity_near, void()); MOCK_METHOD0(handle_enable_inactivity_timeout, void()); MOCK_METHOD0(handle_disable_inactivity_timeout, void()); MOCK_METHOD3(handle_set_inactivity_behavior, void(repowerd::PowerAction power_action, repowerd::PowerSupply power_supply, std::chrono::milliseconds timeout)); MOCK_METHOD0(handle_user_activity_extending_power_state, void()); MOCK_METHOD0(handle_user_activity_changing_power_state, void()); MOCK_METHOD1(handle_set_normal_brightness_value, void(double)); MOCK_METHOD0(handle_enable_autobrightness, void()); MOCK_METHOD0(handle_disable_autobrightness, void()); MOCK_METHOD0(handle_system_resume, void()); MOCK_METHOD1(handle_allow_suspend, void(std::string)); MOCK_METHOD1(handle_disallow_suspend, void(std::string)); void start() { *sessions_activity_log += " start:" + name; } void pause() { *sessions_activity_log += " pause:" + name; } void resume() { *sessions_activity_log += " resume:" + name; } std::shared_ptr const sessions_activity_log; std::string const name; }; struct MockStateMachineFactory : public repowerd::StateMachineFactory { MockStateMachineFactory(std::string const& default_name) : default_name{default_name} { } std::shared_ptr create_state_machine(std::string const& name) { if (mock_state_machine && mock_state_machine->name == name) mock_state_machines.push_back(std::move(mock_state_machine)); else mock_state_machines.push_back(std::make_shared(sessions_activity_log, name)); return mock_state_machines.back(); } std::shared_ptr the_mock_state_machine() { if (!mock_state_machines.empty()) return mock_state_machines.back(); else if (mock_state_machine) return mock_state_machine; else return mock_state_machine = std::make_shared(sessions_activity_log, default_name); } std::shared_ptr the_mock_state_machine(int index) { return mock_state_machines.at(index); } std::string const default_name; std::shared_ptr sessions_activity_log{std::make_shared()}; std::shared_ptr mock_state_machine; std::vector> mock_state_machines; }; struct DaemonConfigWithMockStateMachine : rt::DaemonConfig { std::shared_ptr the_state_machine_factory() override { return the_mock_state_machine_factory(); } std::shared_ptr the_mock_state_machine_factory() { if (!mock_state_machine_factory) { mock_state_machine_factory = std::make_shared( the_fake_session_tracker()->default_session()); } return mock_state_machine_factory; } std::shared_ptr the_mock_state_machine() { the_state_machine_factory(); return mock_state_machine_factory->the_mock_state_machine(); } std::shared_ptr the_mock_state_machine(int index) { return mock_state_machine_factory->the_mock_state_machine(index); } std::shared_ptr mock_state_machine_factory; }; struct ADaemon : testing::Test { DaemonConfigWithMockStateMachine config; std::unique_ptr daemon; std::thread daemon_thread; ~ADaemon() { if (daemon_thread.joinable()) stop_daemon(); } void start_daemon() { start_daemon_with_config(config); } void start_daemon_with_config(repowerd::DaemonConfig& config) { daemon = std::make_unique(config); daemon_thread = rt::run_daemon(*daemon); } void stop_daemon() { daemon->flush(); daemon->stop(); daemon_thread.join(); } void flush_daemon() { daemon->flush(); } void start_daemon_with_second_session_active() { start_daemon(); add_session("s1", repowerd::SessionType::RepowerdCompatible, 42); switch_to_session("s1"); } void add_session(std::string const& session_id, repowerd::SessionType type, pid_t pid) { config.the_fake_session_tracker()->add_session(session_id, type, pid); daemon->flush(); } void switch_to_session(std::string const& session_id) { config.the_fake_session_tracker()->switch_to_session(session_id); daemon->flush(); } void remove_session(std::string const& session_id) { config.the_fake_session_tracker()->remove_session(session_id); daemon->flush(); } std::string sessions_activity_log() { return *config.the_mock_state_machine_factory()->sessions_activity_log; } }; } TEST_F(ADaemon, registers_and_unregisters_timer_alarm_handler) { EXPECT_CALL(config.the_fake_timer()->mock, register_alarm_handler(_)); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_timer().get()); EXPECT_CALL(config.the_fake_timer()->mock, unregister_alarm_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_timer().get()); } TEST_F(ADaemon, notifies_state_machine_of_timer_alarm) { start_daemon(); auto const alarm_id = config.the_fake_timer()->schedule_alarm_in(1s); EXPECT_CALL(*config.the_mock_state_machine(), handle_alarm(alarm_id)); config.the_fake_timer()->advance_by(1s); } TEST_F(ADaemon, registers_starts_and_unregisters_power_button_handler) { InSequence s; EXPECT_CALL(config.the_fake_power_button()->mock, register_power_button_handler(_)); EXPECT_CALL(config.the_fake_power_button()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_power_button().get()); EXPECT_CALL(config.the_fake_power_button()->mock, unregister_power_button_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_power_button().get()); } TEST_F(ADaemon, notifies_state_machine_of_power_button_press) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_power_button_press()); config.the_fake_power_button()->press(); } TEST_F(ADaemon, notifies_state_machine_of_power_button_release) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_power_button_release()); config.the_fake_power_button()->release(); } TEST_F(ADaemon, registers_starts_and_unregisters_user_activity_handler) { InSequence s; EXPECT_CALL(config.the_fake_user_activity()->mock, register_user_activity_handler(_)); EXPECT_CALL(config.the_fake_user_activity()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_user_activity().get()); EXPECT_CALL(config.the_fake_user_activity()->mock, unregister_user_activity_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_user_activity().get()); } TEST_F(ADaemon, notifies_state_machine_of_user_activity_changing_power_state) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_user_activity_changing_power_state()); config.the_fake_user_activity()->perform(repowerd::UserActivityType::change_power_state); } TEST_F(ADaemon, notifies_state_machine_of_user_activity_extending_power_state) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_user_activity_extending_power_state()); config.the_fake_user_activity()->perform(repowerd::UserActivityType::extend_power_state); } TEST_F(ADaemon, registers_starts_and_unregisters_proximity_handler) { EXPECT_CALL(config.the_fake_proximity_sensor()->mock, register_proximity_handler(_)); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_proximity_sensor().get()); EXPECT_CALL(config.the_fake_proximity_sensor()->mock, unregister_proximity_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_proximity_sensor().get()); } TEST_F(ADaemon, notifies_state_machine_of_proximity_far) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_proximity_far()); config.the_fake_proximity_sensor()->emit_proximity_state(repowerd::ProximityState::far); } TEST_F(ADaemon, notifies_state_machine_of_proximity_near) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_proximity_near()); config.the_fake_proximity_sensor()->emit_proximity_state(repowerd::ProximityState::near); } TEST_F(ADaemon, registers_starts_and_unregisters_enable_inactivity_timeout_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_enable_inactivity_timeout_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_enable_inactivity_timeout_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_enable_inactivity_timeout) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_enable_inactivity_timeout()); config.the_fake_client_requests()->emit_enable_inactivity_timeout("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_enable_inactivity_timeout) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_enable_inactivity_timeout()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_enable_inactivity_timeout()).Times(0); config.the_fake_client_requests()->emit_enable_inactivity_timeout("id"); } TEST_F(ADaemon, registers_and_unregisters_disable_inactivity_timeout_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_disable_inactivity_timeout_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_disable_inactivity_timeout_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_disable_inactivity_timeout) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_disable_inactivity_timeout()); config.the_fake_client_requests()->emit_disable_inactivity_timeout("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_disable_inactivity_timeout) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_disable_inactivity_timeout()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_disable_inactivity_timeout()).Times(0); config.the_fake_client_requests()->emit_disable_inactivity_timeout("id"); } TEST_F(ADaemon, registers_and_unregisters_set_inactivity_timeout_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_set_inactivity_timeout_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_set_inactivity_timeout_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_set_inactivity_timeout) { start_daemon(); auto const timeout = 10000ms; EXPECT_CALL(*config.the_mock_state_machine(), handle_set_inactivity_behavior( repowerd::PowerAction::display_off, repowerd::PowerSupply::battery, timeout)); EXPECT_CALL(*config.the_mock_state_machine(), handle_set_inactivity_behavior( repowerd::PowerAction::display_off, repowerd::PowerSupply::line_power, timeout)); config.the_fake_client_requests()->emit_set_inactivity_timeout(timeout); } TEST_F(ADaemon, notifies_inactive_state_machine_of_set_inactivity_timeout) { start_daemon_with_second_session_active(); auto const timeout = 10000ms; EXPECT_CALL(*config.the_mock_state_machine(0), handle_set_inactivity_behavior( repowerd::PowerAction::display_off, _, timeout)).Times(2); EXPECT_CALL(*config.the_mock_state_machine(1), handle_set_inactivity_behavior(_, _, _)).Times(0); config.the_fake_client_requests()->emit_set_inactivity_timeout(timeout); } TEST_F(ADaemon, registers_and_unregisters_disable_autobrightness) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_disable_autobrightness_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_disable_autobrightness_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_disable_autobrightness) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_disable_autobrightness()); config.the_fake_client_requests()->emit_disable_autobrightness(); } TEST_F(ADaemon, notifies_inactive_state_machine_of_disable_autobrightness) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_disable_autobrightness()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_disable_autobrightness()).Times(0); config.the_fake_client_requests()->emit_disable_autobrightness(); } TEST_F(ADaemon, registers_and_unregisters_enable_autobrightness) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_enable_autobrightness_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_enable_autobrightness_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_enable_autobrightness) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_enable_autobrightness()); config.the_fake_client_requests()->emit_enable_autobrightness(); } TEST_F(ADaemon, notifies_inactive_state_machine_of_enable_autobrightness) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_enable_autobrightness()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_enable_autobrightness()).Times(0); config.the_fake_client_requests()->emit_enable_autobrightness(); } TEST_F(ADaemon, registers_and_unregisters_set_normal_brightness_value) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_set_normal_brightness_value_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_set_normal_brightness_value_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_set_normal_brightness_value) { start_daemon(); auto const value = 0.7; EXPECT_CALL(*config.the_mock_state_machine(), handle_set_normal_brightness_value(value)); config.the_fake_client_requests()->emit_set_normal_brightness_value(value); } TEST_F(ADaemon, notifies_inactive_state_machine_of_set_normal_brightness_value) { start_daemon_with_second_session_active(); auto const value = 0.7; EXPECT_CALL(*config.the_mock_state_machine(0), handle_set_normal_brightness_value(value)); EXPECT_CALL(*config.the_mock_state_machine(1), handle_set_normal_brightness_value(_)).Times(0); config.the_fake_client_requests()->emit_set_normal_brightness_value(value); } TEST_F(ADaemon, registers_starts_and_unregisters_allow_suspend_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_allow_suspend_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_allow_suspend_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_allow_suspend_handler) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_allow_suspend("id")); config.the_fake_client_requests()->emit_allow_suspend("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_allow_suspend) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_allow_suspend("id")); EXPECT_CALL(*config.the_mock_state_machine(1), handle_allow_suspend("id")).Times(0); config.the_fake_client_requests()->emit_allow_suspend("id"); } TEST_F(ADaemon, registers_starts_and_unregisters_disallow_suspend_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_requests()->mock, register_disallow_suspend_handler(_)); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); EXPECT_CALL(config.the_fake_client_requests()->mock, unregister_disallow_suspend_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_requests().get()); } TEST_F(ADaemon, notifies_state_machine_of_disallow_suspend_handler) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_disallow_suspend("id")); config.the_fake_client_requests()->emit_disallow_suspend("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_disallow_suspend) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_disallow_suspend("id")); EXPECT_CALL(*config.the_mock_state_machine(1), handle_disallow_suspend("id")).Times(0); config.the_fake_client_requests()->emit_disallow_suspend("id"); } TEST_F(ADaemon, registers_and_unregisters_notification_handler) { InSequence s; EXPECT_CALL(config.the_fake_notification_service()->mock, register_notification_handler(_)); EXPECT_CALL(config.the_fake_notification_service()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_notification_service().get()); EXPECT_CALL(config.the_fake_notification_service()->mock, unregister_notification_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_notification_service().get()); } TEST_F(ADaemon, notifies_state_machine_of_notification) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_notification()); config.the_fake_notification_service()->emit_notification("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_notification) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_notification()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_notification()).Times(0); config.the_fake_notification_service()->emit_notification("id"); } TEST_F(ADaemon, registers_and_unregisters_no_notification_handler) { InSequence s; EXPECT_CALL(config.the_fake_notification_service()->mock, register_notification_done_handler(_)); EXPECT_CALL(config.the_fake_notification_service()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_notification_service().get()); EXPECT_CALL(config.the_fake_notification_service()->mock, unregister_notification_done_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_notification_service().get()); } TEST_F(ADaemon, notifies_state_machine_of_no_notification) { start_daemon(); InSequence s; EXPECT_CALL(*config.the_mock_state_machine(), handle_notification()); EXPECT_CALL(*config.the_mock_state_machine(), handle_no_notification()); config.the_fake_notification_service()->emit_notification("id"); config.the_fake_notification_service()->emit_notification_done("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_no_notification) { start_daemon_with_second_session_active(); InSequence s; EXPECT_CALL(*config.the_mock_state_machine(0), handle_notification()); EXPECT_CALL(*config.the_mock_state_machine(0), handle_no_notification()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_no_notification()).Times(0); config.the_fake_notification_service()->emit_notification("id"); config.the_fake_notification_service()->emit_notification_done("id"); } TEST_F(ADaemon, notifies_inactive_state_machine_of_no_notification_if_notification_was_sent_while_active) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_notification()); config.the_fake_notification_service()->emit_notification("id"); flush_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_voice_call_service().get()); add_session("s1", repowerd::SessionType::RepowerdCompatible, 42); switch_to_session("s1"); InSequence s; EXPECT_CALL(*config.the_mock_state_machine(0), handle_no_notification()); EXPECT_CALL(*config.the_mock_state_machine(1), handle_no_notification()).Times(0); config.the_fake_notification_service()->emit_notification_done("id"); } TEST_F(ADaemon, registers_and_unregisters_active_call_handler) { InSequence s; EXPECT_CALL(config.the_fake_voice_call_service()->mock, register_active_call_handler(_)); EXPECT_CALL(config.the_fake_voice_call_service()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_voice_call_service().get()); EXPECT_CALL(config.the_fake_voice_call_service()->mock, unregister_active_call_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_voice_call_service().get()); } TEST_F(ADaemon, notifies_state_machine_of_active_call) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_active_call()); config.the_fake_voice_call_service()->emit_active_call(); } TEST_F(ADaemon, registers_and_unregisters_no_active_call_handler) { InSequence s; EXPECT_CALL(config.the_fake_voice_call_service()->mock, register_no_active_call_handler(_)); EXPECT_CALL(config.the_fake_voice_call_service()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_voice_call_service().get()); EXPECT_CALL(config.the_fake_voice_call_service()->mock, unregister_no_active_call_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_voice_call_service().get()); } TEST_F(ADaemon, notifies_state_machine_of_no_active_call) { start_daemon(); InSequence s; EXPECT_CALL(*config.the_mock_state_machine(), handle_active_call()); EXPECT_CALL(*config.the_mock_state_machine(), handle_no_active_call()); config.the_fake_voice_call_service()->emit_active_call(); config.the_fake_voice_call_service()->emit_no_active_call(); } TEST_F(ADaemon, registers_and_unregisters_power_source_change_handler) { InSequence s; EXPECT_CALL(config.the_fake_power_source()->mock, register_power_source_change_handler(_)); EXPECT_CALL(config.the_fake_power_source()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_power_source().get()); EXPECT_CALL(config.the_fake_power_source()->mock, unregister_power_source_change_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_power_source().get()); } TEST_F(ADaemon, notifies_state_machine_of_power_source_change) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_power_source_change()); config.the_fake_power_source()->emit_power_source_change(); } TEST_F(ADaemon, registers_and_unregisters_power_source_critical_handler) { InSequence s; EXPECT_CALL(config.the_fake_power_source()->mock, register_power_source_critical_handler(_)); EXPECT_CALL(config.the_fake_power_source()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_power_source().get()); EXPECT_CALL(config.the_fake_power_source()->mock, unregister_power_source_critical_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_power_source().get()); } TEST_F(ADaemon, notifies_state_machine_of_power_source_critical) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_power_source_critical()); config.the_fake_power_source()->emit_power_source_critical(); } TEST_F(ADaemon, registers_and_unregisters_active_session_changed_handler) { InSequence s; EXPECT_CALL(config.the_fake_session_tracker()->mock, register_active_session_changed_handler(_)); EXPECT_CALL(config.the_fake_session_tracker()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_session_tracker().get()); EXPECT_CALL(config.the_fake_session_tracker()->mock, unregister_active_session_changed_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_session_tracker().get()); } TEST_F(ADaemon, registers_and_unregisters_session_removed_handler) { InSequence s; EXPECT_CALL(config.the_fake_session_tracker()->mock, register_session_removed_handler(_)); EXPECT_CALL(config.the_fake_session_tracker()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_session_tracker().get()); EXPECT_CALL(config.the_fake_session_tracker()->mock, unregister_session_removed_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_session_tracker().get()); } TEST_F(ADaemon, starts_session_tracker_processing_before_per_session_components) { Expectation session = EXPECT_CALL(config.the_fake_session_tracker()->mock, start_processing()); EXPECT_CALL(config.the_fake_client_requests()->mock, start_processing()) .After(session); EXPECT_CALL(config.the_fake_notification_service()->mock, start_processing()) .After(session); start_daemon(); } TEST_F(ADaemon, makes_null_session_active_if_active_is_removed) { start_daemon(); remove_session( config.the_fake_session_tracker()->default_session()); EXPECT_CALL(*config.the_mock_state_machine(), handle_power_button_press()).Times(0); config.the_fake_power_button()->press(); } TEST_F(ADaemon, pauses_active_session_before_removing_it) { auto const start = [](std::string name) { return " start:" + name; }; auto const pause = [](std::string name) { return " pause:" + name; }; start_daemon(); auto const default_session = config.the_fake_session_tracker()->default_session(); remove_session( config.the_fake_session_tracker()->default_session()); EXPECT_THAT(sessions_activity_log(), StrEq(start(default_session) + pause(default_session))); } TEST_F(ADaemon, starts_session_on_first_switch) { start_daemon(); add_session("s1", repowerd::SessionType::RepowerdCompatible, 42); switch_to_session("s1"); EXPECT_THAT(sessions_activity_log(), HasSubstr("start:s1")); EXPECT_THAT(sessions_activity_log(), Not(HasSubstr("resume:s1"))); } TEST_F(ADaemon, starts_pauses_resumes_sessions_on_switch) { auto const start = [](std::string name) { return " start:" + name; }; auto const pause = [](std::string name) { return " pause:" + name; }; auto const resume = [](std::string name) { return " resume:" + name; }; start_daemon(); auto const default_session = config.the_fake_session_tracker()->default_session(); add_session("s1", repowerd::SessionType::RepowerdCompatible, 42); switch_to_session("s1"); EXPECT_THAT(sessions_activity_log(), StrEq(start(default_session) + pause(default_session) + start("s1"))); switch_to_session(default_session); EXPECT_THAT(sessions_activity_log(), StrEq(start(default_session) + pause(default_session) + start("s1") + pause("s1") + resume(default_session))); } TEST_F(ADaemon, registers_starts_and_unregisters_lid_handler) { InSequence s; EXPECT_CALL(config.the_fake_lid()->mock, register_lid_handler(_)); EXPECT_CALL(config.the_fake_lid()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_lid().get()); EXPECT_CALL(config.the_fake_lid()->mock, unregister_lid_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_lid().get()); } TEST_F(ADaemon, notifies_state_machine_of_lid_closed) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_lid_closed()); config.the_fake_lid()->close(); } TEST_F(ADaemon, notifies_state_machine_of_lid_open) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_lid_open()); config.the_fake_lid()->open(); } TEST_F(ADaemon, registers_and_unregisters_set_inactivity_behavior_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_settings()->mock, register_set_inactivity_behavior_handler(_)); EXPECT_CALL(config.the_fake_client_settings()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_settings().get()); EXPECT_CALL(config.the_fake_client_settings()->mock, unregister_set_inactivity_behavior_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_settings().get()); } TEST_F(ADaemon, notifies_state_machine_of_set_inactivity_behavior) { start_daemon(); auto const power_action = repowerd::PowerAction::display_off; auto const power_supply = repowerd::PowerSupply::line_power; auto const timeout = 10000ms; EXPECT_CALL(*config.the_mock_state_machine(), handle_set_inactivity_behavior(power_action, power_supply, timeout)); config.the_fake_client_settings()->emit_set_inactivity_behavior( power_action, power_supply, timeout); } TEST_F(ADaemon, notifies_inactive_state_machine_of_set_inactivity_behavior) { start_daemon_with_second_session_active(); auto const power_action = repowerd::PowerAction::display_off; auto const power_supply = repowerd::PowerSupply::line_power; auto const timeout = 10000ms; EXPECT_CALL(*config.the_mock_state_machine(0), handle_set_inactivity_behavior(power_action, power_supply, timeout)); EXPECT_CALL(*config.the_mock_state_machine(1), handle_set_inactivity_behavior(_, _, _)).Times(0); config.the_fake_client_settings()->emit_set_inactivity_behavior( power_action, power_supply, timeout); } TEST_F(ADaemon, registers_and_unregisters_set_lid_behavior_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_settings()->mock, register_set_lid_behavior_handler(_)); EXPECT_CALL(config.the_fake_client_settings()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_settings().get()); EXPECT_CALL(config.the_fake_client_settings()->mock, unregister_set_lid_behavior_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_settings().get()); } TEST_F(ADaemon, notifies_state_machine_of_set_lid_behavior) { start_daemon(); auto const power_action = repowerd::PowerAction::display_off; auto const power_supply = repowerd::PowerSupply::line_power; EXPECT_CALL(*config.the_mock_state_machine(), handle_set_lid_behavior(power_action, power_supply)); config.the_fake_client_settings()->emit_set_lid_behavior( power_action, power_supply); } TEST_F(ADaemon, notifies_inactive_state_machine_of_set_lid_behavior) { start_daemon_with_second_session_active(); auto const power_action = repowerd::PowerAction::display_off; auto const power_supply = repowerd::PowerSupply::line_power; EXPECT_CALL(*config.the_mock_state_machine(0), handle_set_lid_behavior(power_action, power_supply)); EXPECT_CALL(*config.the_mock_state_machine(1), handle_set_lid_behavior(_, _)).Times(0); config.the_fake_client_settings()->emit_set_lid_behavior( power_action, power_supply); } TEST_F(ADaemon, registers_and_unregisters_set_critical_power_behavior_handler) { InSequence s; EXPECT_CALL(config.the_fake_client_settings()->mock, register_set_critical_power_behavior_handler(_)); EXPECT_CALL(config.the_fake_client_settings()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_settings().get()); EXPECT_CALL(config.the_fake_client_settings()->mock, unregister_set_critical_power_behavior_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_client_settings().get()); } TEST_F(ADaemon, notifies_state_machine_of_set_critical_power_behavior) { start_daemon(); auto const power_action = repowerd::PowerAction::suspend; EXPECT_CALL(*config.the_mock_state_machine(), handle_set_critical_power_behavior(power_action)); config.the_fake_client_settings()->emit_set_critical_power_behavior( power_action); } TEST_F(ADaemon, notifies_inactive_state_machine_of_set_critical_power_behavior) { start_daemon_with_second_session_active(); auto const power_action = repowerd::PowerAction::suspend; EXPECT_CALL(*config.the_mock_state_machine(0), handle_set_critical_power_behavior(power_action)); EXPECT_CALL(*config.the_mock_state_machine(1), handle_set_critical_power_behavior(_)).Times(0); config.the_fake_client_settings()->emit_set_critical_power_behavior( power_action); } TEST_F(ADaemon, registers_and_unregisters_system_resume_handler) { InSequence s; EXPECT_CALL(config.the_fake_system_power_control()->mock, register_system_resume_handler(_)); EXPECT_CALL(config.the_fake_system_power_control()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_system_power_control().get()); EXPECT_CALL(config.the_fake_system_power_control()->mock, unregister_system_resume_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_system_power_control().get()); } TEST_F(ADaemon, notifies_state_machine_of_system_resume) { start_daemon(); EXPECT_CALL(*config.the_mock_state_machine(), handle_system_resume()); config.the_fake_system_power_control()->emit_system_resume(); } TEST_F(ADaemon, registers_and_unregisters_system_allow_suspend_handler) { InSequence s; EXPECT_CALL(config.the_fake_system_power_control()->mock, register_system_allow_suspend_handler(_)); EXPECT_CALL(config.the_fake_system_power_control()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_system_power_control().get()); EXPECT_CALL(config.the_fake_system_power_control()->mock, unregister_system_allow_suspend_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_system_power_control().get()); } TEST_F(ADaemon, notifies_all_state_machines_of_system_allow_suspend) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_allow_suspend("FakeSystemPowerControl")); EXPECT_CALL(*config.the_mock_state_machine(1), handle_allow_suspend("FakeSystemPowerControl")); config.the_fake_system_power_control()->emit_system_allow_suspend(); } TEST_F(ADaemon, registers_and_unregisters_system_disallow_suspend_handler) { InSequence s; EXPECT_CALL(config.the_fake_system_power_control()->mock, register_system_disallow_suspend_handler(_)); EXPECT_CALL(config.the_fake_system_power_control()->mock, start_processing()); start_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_system_power_control().get()); EXPECT_CALL(config.the_fake_system_power_control()->mock, unregister_system_disallow_suspend_handler()); stop_daemon(); testing::Mock::VerifyAndClearExpectations(config.the_fake_system_power_control().get()); } TEST_F(ADaemon, notifies_all_state_machines_of_system_disallow_suspend) { start_daemon_with_second_session_active(); EXPECT_CALL(*config.the_mock_state_machine(0), handle_disallow_suspend("FakeSystemPowerControl")); EXPECT_CALL(*config.the_mock_state_machine(1), handle_disallow_suspend("FakeSystemPowerControl")); config.the_fake_system_power_control()->emit_system_disallow_suspend(); } repowerd-2023.07/tests/core-tests/test_fake_timer.cpp000066400000000000000000000075641446034100200226270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fake_timer.h" #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct AFakeTimer : testing::Test { rt::FakeTimer fake_timer; repowerd::HandlerRegistration const reg{ fake_timer.register_alarm_handler( [this](repowerd::AlarmId id) { alarm_handler(id); })}; MOCK_METHOD1(alarm_handler, void(repowerd::AlarmId id)); }; } TEST_F(AFakeTimer, gives_different_ids_to_active_alarms) { using namespace testing; auto const id1 = fake_timer.schedule_alarm_in(10s); auto const id2 = fake_timer.schedule_alarm_in(10s); auto const id3 = fake_timer.schedule_alarm_in(10s); EXPECT_THAT(id1, Ne(id2)); EXPECT_THAT(id1, Ne(id3)); EXPECT_THAT(id2, Ne(id3)); } TEST_F(AFakeTimer, notifies_when_alarm_triggers) { auto const id = fake_timer.schedule_alarm_in(10s); EXPECT_CALL(*this, alarm_handler(id)); fake_timer.advance_by(10s); } TEST_F(AFakeTimer, notifies_in_order_when_multiple_alarms_trigger) { auto const id1 = fake_timer.schedule_alarm_in(10s); auto const id2 = fake_timer.schedule_alarm_in(10s); auto const id3 = fake_timer.schedule_alarm_in(20s); auto const id4 = fake_timer.schedule_alarm_in(30s); testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id1)); EXPECT_CALL(*this, alarm_handler(id2)); EXPECT_CALL(*this, alarm_handler(id3)); EXPECT_CALL(*this, alarm_handler(id4)); fake_timer.advance_by(30s); } TEST_F(AFakeTimer, does_not_notify_for_alarms_not_triggered) { auto const id1 = fake_timer.schedule_alarm_in(10s); auto const id2 = fake_timer.schedule_alarm_in(20s); auto const id3 = fake_timer.schedule_alarm_in(30s); testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id1)); EXPECT_CALL(*this, alarm_handler(id2)); EXPECT_CALL(*this, alarm_handler(id3)).Times(0); fake_timer.advance_by(29s); } TEST_F(AFakeTimer, notifies_for_alarms_added_after_advancing) { auto const id1 = fake_timer.schedule_alarm_in(10s); EXPECT_CALL(*this, alarm_handler(id1)); fake_timer.advance_by(30s); auto const id2 = fake_timer.schedule_alarm_in(5s); auto const id3 = fake_timer.schedule_alarm_in(6s); testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id2)); EXPECT_CALL(*this, alarm_handler(id3)); fake_timer.advance_by(10s); } TEST_F(AFakeTimer, updates_now_when_advanced) { auto const advance = 10ms; auto const then = fake_timer.now(); fake_timer.advance_by(advance); auto const now = fake_timer.now(); EXPECT_THAT(now - then, testing::Eq(advance)); } TEST_F(AFakeTimer, does_not_notify_for_cancelled_alarms) { auto const id1 = fake_timer.schedule_alarm_in(10s); auto const id2 = fake_timer.schedule_alarm_in(10s); auto const id3 = fake_timer.schedule_alarm_in(20s); auto const id4 = fake_timer.schedule_alarm_in(30s); testing::InSequence s; EXPECT_CALL(*this, alarm_handler(id1)); EXPECT_CALL(*this, alarm_handler(id2)).Times(0); EXPECT_CALL(*this, alarm_handler(id3)); EXPECT_CALL(*this, alarm_handler(id4)).Times(0); fake_timer.cancel_alarm(id4); fake_timer.cancel_alarm(id2); fake_timer.advance_by(30s); } repowerd-2023.07/tests/core-tests/test_handler_registration.cpp000066400000000000000000000053651446034100200247250ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "src/core/handler_registration.h" #include #include TEST(AHandlerRegistration, calls_unregistration_callback_when_destroyed) { bool unregistered = false; { repowerd::HandlerRegistration reg{[&] { unregistered = true; }}; EXPECT_FALSE(unregistered); } EXPECT_TRUE(unregistered); } TEST(AHandlerRegistration, calls_unregistration_callback_when_overwritten) { bool unregistered = false; repowerd::HandlerRegistration reg{[&] { unregistered = true; }}; EXPECT_FALSE(unregistered); reg = repowerd::HandlerRegistration{[]{}}; EXPECT_TRUE(unregistered); } TEST(AHandlerRegistration, move_construction_moves_properly) { bool unregistered = false; auto reg1 = std::make_unique([&] { unregistered = true; }); auto reg2 = std::make_unique(std::move(*reg1)); reg1.reset(); EXPECT_FALSE(unregistered); reg2.reset(); EXPECT_TRUE(unregistered); } TEST(AHandlerRegistration, move_assignment_moves_properly) { bool unregistered1 = false; bool unregistered2 = false; auto reg1 = std::make_unique([&] { unregistered1 = true; }); auto reg2 = std::make_unique([&] { unregistered2 = true; }); EXPECT_FALSE(unregistered1); EXPECT_FALSE(unregistered2); *reg2 = std::move(*reg1); EXPECT_FALSE(unregistered1); EXPECT_TRUE(unregistered2); reg1.reset(); EXPECT_FALSE(unregistered1); EXPECT_TRUE(unregistered2); reg2.reset(); EXPECT_TRUE(unregistered1); EXPECT_TRUE(unregistered2); } TEST(AHandlerRegistration, move_assignment_handles_self_assignment) { bool unregistered = false; { repowerd::HandlerRegistration reg{[&] { unregistered = true; }}; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wself-move" reg = std::move(reg); #pragma GCC diagnostic pop EXPECT_FALSE(unregistered); } EXPECT_TRUE(unregistered); } repowerd-2023.07/tests/core-tests/test_lid.cpp000066400000000000000000000052021446034100200212540ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "fake_display_information.h" #include "fake_system_power_control.h" #include namespace rt = repowerd::test; using namespace testing; namespace { struct ALid : rt::AcceptanceTest { void activate_external_display() { config.the_fake_display_information()->set_has_active_external_displays(true); } }; } TEST_F(ALid, closed_turns_off_display_beforing_suspending) { turn_on_display(); InSequence s; expect_display_turns_off(); expect_system_suspends(); close_lid(); } TEST_F(ALid, closed_suspends_regardless_of_suspend_disallowances) { turn_on_display(); client_request_disallow_suspend(); emit_system_disallow_suspend(); InSequence s; expect_display_turns_off(); expect_system_suspends(); close_lid(); } TEST_F(ALid, closed_is_logged) { close_lid(); EXPECT_TRUE(log_contains_line({"lid_closed"})); } TEST_F(ALid, opened_turns_on_display) { expect_display_turns_on(); open_lid(); } TEST_F(ALid, opened_is_logged) { open_lid(); EXPECT_TRUE(log_contains_line({"lid_open"})); } TEST_F(ALid, closed_turns_off_internal_display_but_does_not_suspend_if_external_displays_active) { activate_external_display(); turn_on_display(); expect_internal_display_turns_off(); expect_no_system_power_change(); close_lid(); } TEST_F(ALid, opened_turns_on_internal_display_if_not_suspended) { activate_external_display(); turn_on_display(); close_lid(); expect_display_brightens(); expect_internal_display_turns_on(); open_lid(); } TEST_F(ALid, while_closed_prevents_internal_display_from_turning_on) { activate_external_display(); turn_on_display(); close_lid(); expect_display_turns_off(); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); expect_external_display_turns_on(); perform_user_activity_changing_power_state(); } repowerd-2023.07/tests/core-tests/test_modem_power_control.cpp000066400000000000000000000036431446034100200245700ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "mock_modem_power_control.h" #include namespace rt = repowerd::test; namespace { struct AModemPowerControl : rt::AcceptanceTest { void expect_modem_set_to_low_power_mode() { EXPECT_CALL(*config.the_mock_modem_power_control(), set_low_power_mode()); } void expect_modem_set_to_normal_power_mode() { EXPECT_CALL(*config.the_mock_modem_power_control(), set_normal_power_mode()); } void expect_no_modem_power_mode_change() { EXPECT_CALL(*config.the_mock_modem_power_control(), set_low_power_mode()).Times(0); EXPECT_CALL(*config.the_mock_modem_power_control(), set_normal_power_mode()).Times(0); } }; } TEST_F(AModemPowerControl, is_set_to_normal_power_mode_when_display_turns_on) { expect_modem_set_to_normal_power_mode(); turn_on_display(); } TEST_F(AModemPowerControl, is_set_to_low_power_mode_when_display_turns_off) { turn_on_display(); expect_modem_set_to_low_power_mode(); turn_off_display(); } TEST_F(AModemPowerControl, is_left_to_normal_power_mode_when_display_turns_off_due_to_proximity) { turn_on_display(); expect_no_modem_power_mode_change(); emit_proximity_state_near(); } repowerd-2023.07/tests/core-tests/test_notification.cpp000066400000000000000000000323541446034100200232020ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct ANotification : rt::AcceptanceTest { }; } TEST_F(ANotification, turns_on_display) { expect_display_turns_on(); emit_notification(); verify_expectations(); } TEST_F(ANotification, turns_off_display_after_post_notification_timeout_when_done) { expect_display_turns_on(); emit_notification(); verify_expectations(); expect_no_display_power_change(); emit_notification_done(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, does_not_turn_on_display_if_display_is_already_on) { turn_on_display(); expect_no_display_power_change(); emit_notification(); } TEST_F(ANotification, keeps_display_on_if_display_is_already_on) { turn_on_display(); expect_no_display_power_change(); emit_notification(); advance_time_by(10h); } TEST_F(ANotification, does_not_dim_display_after_timeout) { expect_display_turns_on(); emit_notification(); verify_expectations(); expect_no_display_brightness_change(); emit_notification_done(); advance_time_by(user_inactivity_post_notification_display_off_timeout - 1ms); } TEST_F(ANotification, extends_existing_shorter_timeout) { turn_on_display(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); emit_notification(); emit_notification_done(); expect_no_display_power_change(); advance_time_by(1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, does_not_reduce_existing_longer_timeout) { turn_on_display(); advance_time_by( user_inactivity_normal_display_off_timeout - user_inactivity_post_notification_display_off_timeout - 1ms); emit_notification(); emit_notification_done(); expect_no_display_power_change(); advance_time_by(user_inactivity_post_notification_display_off_timeout); verify_expectations(); } TEST_F(ANotification, does_not_turn_on_display_when_proximity_is_near) { set_proximity_state_near(); expect_no_display_power_change(); emit_notification(); } TEST_F(ANotification, does_not_schedule_inactivity_timeout_when_proximity_is_near) { set_proximity_state_near(); expect_no_display_power_change(); emit_notification(); emit_notification_done(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, timeout_is_extended_by_user_activity) { expect_display_turns_on(); emit_notification(); emit_notification_done(); verify_expectations(); expect_no_display_power_change(); perform_user_activity_extending_power_state(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(ANotification, allows_power_button_to_turn_off_display) { expect_display_turns_on(); emit_notification(); verify_expectations(); expect_display_turns_off(); press_power_button(); release_power_button(); verify_expectations(); } TEST_F(ANotification, brightens_dim_display) { turn_on_display(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_brightens(); emit_notification(); } TEST_F(ANotification, turns_off_display_when_done_if_a_client_disables_inactivity_timeout_and_the_display_was_off) { expect_display_turns_on(); emit_notification(); verify_expectations(); expect_no_display_power_change(); client_request_disable_inactivity_timeout(); emit_notification_done(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, turns_off_display_when_done_if_a_client_sets_infinite_inactivity_timeout_and_the_display_was_off) { expect_display_turns_on(); emit_notification(); client_request_set_inactivity_timeout(infinite_timeout); emit_notification_done(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, turns_off_display_when_done_if_a_client_has_previously_disabled_inactivity_timeout_and_the_display_was_off) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); turn_off_display(); expect_display_turns_on(); emit_notification(); emit_notification_done(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, turns_off_display_when_done_if_a_client_has_previously_set_infinite_inactivity_timeout_and_the_display_was_off) { client_request_set_inactivity_timeout(infinite_timeout); expect_display_turns_on(); emit_notification(); emit_notification_done(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, does_not_turn_off_display_when_done_if_a_client_has_disabled_inactivity_timeout_and_the_display_was_on) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); expect_no_display_power_change(); emit_notification(); emit_notification_done(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, does_not_turn_off_display_when_done_if_a_client_has_set_infinite_timeout_and_the_display_was_on) { client_request_set_inactivity_timeout(infinite_timeout); turn_on_display(); expect_no_display_power_change(); emit_notification(); emit_notification_done(); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, event_notifies_of_display_power_change) { expect_display_power_on_notification( repowerd::DisplayPowerChangeReason::notification); emit_notification(); verify_expectations(); emit_notification_done(); expect_display_power_off_notification( repowerd::DisplayPowerChangeReason::activity); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, turns_display_on_for_reduced_timeout_if_proximity_uncovered) { set_proximity_state_near(); emit_notification(); expect_display_turns_on(); emit_proximity_state_far_if_enabled(); emit_notification_done(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_reduced_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(ANotification, disables_proximity_handling_after_proximity_uncovered) { expect_display_turns_on(); set_proximity_state_near(); emit_notification(); emit_proximity_state_far_if_enabled(); verify_expectations(); expect_no_display_power_change(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); emit_proximity_state_near_if_enabled(); } TEST_F(ANotification, does_not_disable_proximity_handling_after_proximity_uncovered_if_call_is_active) { set_proximity_state_near(); emit_active_call(); emit_notification(); emit_proximity_state_far_if_enabled(); expect_display_turns_off(); emit_proximity_state_near_if_enabled(); verify_expectations(); expect_display_turns_on(); emit_proximity_state_far_if_enabled(); verify_expectations(); } TEST_F(ANotification, just_before_user_activity_timeout_does_not_turn_off_display_if_inactivity_is_disabled_and_display_was_turned_on_by_notification) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); turn_off_display(); expect_display_turns_on(); emit_notification(); expect_display_brightens(); perform_user_activity_extending_power_state(); emit_notification_done(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); emit_notification(); emit_notification_done(); advance_time_by(user_inactivity_post_notification_display_off_timeout); verify_expectations(); } TEST_F(ANotification, after_user_activity_timeout_does_not_turn_off_display_if_inactivity_is_disabled_and_display_was_turned_on_by_notification) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); turn_off_display(); expect_display_turns_on(); emit_notification(); expect_display_brightens(); perform_user_activity_extending_power_state(); emit_notification_done(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout); emit_notification(); emit_notification_done(); advance_time_by(user_inactivity_post_notification_display_off_timeout); verify_expectations(); } TEST_F(ANotification, does_not_keep_the_display_on_longer_than_the_notification_expiration_timeout) { expect_display_turns_on(); emit_notification(); verify_expectations(); expect_no_display_power_change(); advance_time_by(notification_expiration_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); // timer needs extra kick to apply alarm just set in previous advancement advance_time_by(0ms); verify_expectations(); expect_no_display_power_change(); emit_notification_done(); verify_expectations(); } TEST_F(ANotification, does_not_keep_the_display_on_longer_than_the_notification_expiration_timeout_if_inactivity_is_disabled) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); turn_off_display(); expect_display_turns_on(); emit_notification(); verify_expectations(); expect_no_display_power_change(); advance_time_by(notification_expiration_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); // timer needs extra kick to apply alarm just set in previous advancement advance_time_by(0ms); verify_expectations(); expect_no_display_power_change(); emit_notification_done(); verify_expectations(); } TEST_F(ANotification, does_not_keep_the_display_on_longer_than_the_notification_expiration_timeout_if_inactivity_timeout_is_infinite) { client_request_set_inactivity_timeout(infinite_timeout); expect_display_turns_on(); emit_notification(); verify_expectations(); expect_no_display_power_change(); advance_time_by(notification_expiration_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); // timer needs extra kick to apply alarm just set in previous advancement advance_time_by(0ms); verify_expectations(); expect_no_display_power_change(); emit_notification_done(); verify_expectations(); } TEST_F(ANotification, keeps_display_on_until_all_done) { std::string const id1{"id1"}; std::string const id2{"id2"}; std::string const id3{"id3"}; expect_display_turns_on(); emit_notification(id1); verify_expectations(); expect_display_brightens(); emit_notification(id2); verify_expectations(); expect_display_brightens(); emit_notification(id3); verify_expectations(); expect_no_display_power_change(); emit_notification_done(id3); emit_notification_done(id1); advance_time_by(user_inactivity_post_notification_display_off_timeout); verify_expectations(); expect_display_turns_off(); emit_notification_done(id2); advance_time_by(user_inactivity_post_notification_display_off_timeout); } TEST_F(ANotification, is_logged) { emit_notification(); EXPECT_TRUE(log_contains_line({"notification"})); } TEST_F(ANotification, all_done_is_logged) { emit_notification(); emit_notification_done(); EXPECT_TRUE(log_contains_line({"no_notification"})); } TEST_F(ANotification, expiration_timeout_alarm_is_logged) { emit_notification(); advance_time_by(notification_expiration_timeout); EXPECT_TRUE(log_contains_line({"alarm", "notification", "expiration"})); } repowerd-2023.07/tests/core-tests/test_performance_booster.cpp000066400000000000000000000027411446034100200245470ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "mock_performance_booster.h" #include namespace rt = repowerd::test; namespace { struct APerformanceBooster : rt::AcceptanceTest { void expect_enable_interactive_mode() { EXPECT_CALL(*config.the_mock_performance_booster(), enable_interactive_mode()); } void expect_disable_interactive_mode() { EXPECT_CALL(*config.the_mock_performance_booster(), disable_interactive_mode()); } }; } TEST_F(APerformanceBooster, interactive_mode_is_enabled_when_display_turns_on) { expect_enable_interactive_mode(); turn_on_display(); } TEST_F(APerformanceBooster, interactive_mode_is_disabled_when_display_turns_off) { turn_on_display(); expect_disable_interactive_mode(); turn_off_display(); } repowerd-2023.07/tests/core-tests/test_power_button.cpp000066400000000000000000000075771446034100200232540ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct APowerButton : rt::AcceptanceTest { }; } TEST_F(APowerButton, press_turns_on_display) { expect_display_turns_on(); press_power_button(); } TEST_F(APowerButton, release_after_press_that_turns_on_display_does_nothing) { expect_display_turns_on(); press_power_button(); release_power_button(); } TEST_F(APowerButton, stray_release_is_ignored_when_display_is_off) { expect_no_display_power_change(); release_power_button(); } TEST_F(APowerButton, stray_release_is_ignored_when_display_is_on) { turn_on_display(); expect_no_display_power_change(); release_power_button(); } TEST_F(APowerButton, press_does_nothing_if_display_is_already_on) { turn_on_display(); expect_no_display_power_change(); press_power_button(); } TEST_F(APowerButton, short_press_turns_off_display_it_is_already_on) { turn_on_display(); expect_display_turns_off(); press_power_button(); release_power_button(); } TEST_F(APowerButton, long_press_turns_on_display_and_notifies_if_display_is_off) { expect_display_turns_on(); expect_long_press_notification(); press_power_button(); advance_time_by(power_button_long_press_timeout); } TEST_F(APowerButton, long_press_notifies_if_display_is_on) { turn_on_display(); expect_no_display_power_change(); expect_long_press_notification(); press_power_button(); advance_time_by(power_button_long_press_timeout); } TEST_F(APowerButton, short_press_can_change_display_power_state_after_long_press) { turn_on_display(); expect_long_press_notification(); press_power_button(); advance_time_by(power_button_long_press_timeout); release_power_button(); verify_expectations(); expect_display_turns_off(); press_power_button(); release_power_button(); verify_expectations(); expect_display_turns_on(); press_power_button(); release_power_button(); verify_expectations(); } TEST_F(APowerButton, event_notifies_of_display_power_change) { expect_display_power_on_notification( repowerd::DisplayPowerChangeReason::power_button); press_power_button(); release_power_button(); verify_expectations(); expect_display_power_off_notification( repowerd::DisplayPowerChangeReason::power_button); press_power_button(); release_power_button(); } TEST_F(APowerButton, press_turns_on_display_and_keeps_it_on_forever_if_inactivity_timeout_is_infinite) { client_request_set_inactivity_timeout(infinite_timeout); turn_on_display(); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(1h); } TEST_F(APowerButton, press_is_logged) { press_power_button(); EXPECT_TRUE(log_contains_line({"power_button_press"})); } TEST_F(APowerButton, release_is_logged) { release_power_button(); EXPECT_TRUE(log_contains_line({"power_button_release"})); } TEST_F(APowerButton, long_press_is_logged) { press_power_button(); advance_time_by(power_button_long_press_timeout); EXPECT_TRUE(log_contains_line({"long_press"})); } repowerd-2023.07/tests/core-tests/test_power_source.cpp000066400000000000000000000062441446034100200232270ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct APowerSource : rt::AcceptanceTest { }; } TEST_F(APowerSource, change_turns_on_display_for_reduced_timeout) { expect_display_turns_on(); emit_power_source_change(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_reduced_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(APowerSource, change_brightens_display_if_it_is_already_on) { turn_on_display(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_no_display_power_change(); expect_display_brightens(); emit_power_source_change(); } TEST_F(APowerSource, change_reschedules_timeout_if_display_is_already_on) { turn_on_display(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); emit_power_source_change(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(APowerSource, change_does_not_turn_off_display_if_inactivity_timeout_is_disabled_and_display_was_on) { client_request_disable_inactivity_timeout(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout); emit_power_source_change(); advance_time_by(user_inactivity_reduced_display_off_timeout); verify_expectations(); } TEST_F(APowerSource, change_turns_off_display_if_inactivity_timeout_is_disabled_and_display_was_off) { client_request_disable_inactivity_timeout(); turn_off_display(); expect_display_turns_on(); emit_power_source_change(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_reduced_display_off_timeout); } TEST_F(APowerSource, critical_state_powers_off_system) { expect_system_powers_off(); emit_power_source_critical(); } TEST_F(APowerSource, change_is_logged) { emit_power_source_change(); EXPECT_TRUE(log_contains_line({"power_source_change"})); } TEST_F(APowerSource, critical_state_is_logged) { emit_power_source_critical(); EXPECT_TRUE(log_contains_line({"power_source_critical"})); } repowerd-2023.07/tests/core-tests/test_proximity_sensor.cpp000066400000000000000000000047511446034100200241510ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include namespace rt = repowerd::test; namespace { struct APromixitySensor : rt::AcceptanceTest { }; } TEST_F(APromixitySensor, near_state_does_not_allow_display_to_turn_on_due_to_user_activity) { expect_no_display_power_change(); set_proximity_state_near(); perform_user_activity_changing_power_state(); } TEST_F(APromixitySensor, near_state_allows_display_to_turn_on_due_to_power_button) { expect_display_turns_on(); set_proximity_state_near(); press_power_button(); release_power_button(); } TEST_F(APromixitySensor, far_event_turns_on_display) { expect_display_turns_on(); emit_proximity_state_far(); } TEST_F(APromixitySensor, far_event_has_no_effect_if_display_is_on) { turn_on_display(); expect_no_display_power_change(); emit_proximity_state_far(); } TEST_F(APromixitySensor, near_event_turns_off_display) { turn_on_display(); expect_display_turns_off(); emit_proximity_state_near(); } TEST_F(APromixitySensor, near_event_has_no_effect_if_display_is_off) { expect_no_display_power_change(); emit_proximity_state_near(); } TEST_F(APromixitySensor, event_notifies_of_display_power_change) { turn_on_display(); expect_display_power_off_notification( repowerd::DisplayPowerChangeReason::proximity); emit_proximity_state_near(); verify_expectations(); expect_display_power_on_notification( repowerd::DisplayPowerChangeReason::proximity); emit_proximity_state_far(); } TEST_F(APromixitySensor, near_event_is_logged) { emit_proximity_state_near(); EXPECT_TRUE(log_contains_line({"proximity", "near"})); } TEST_F(APromixitySensor, far_event_is_logged) { emit_proximity_state_far(); EXPECT_TRUE(log_contains_line({"proximity", "far"})); } repowerd-2023.07/tests/core-tests/test_session.cpp000066400000000000000000000250311446034100200221710ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "default_pid.h" #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct ASession : rt::AcceptanceTest { ASession() { add_incompatible_session(incompatible(0), incompatible_pid(0)); add_compatible_session(compatible(0), compatible_pid(0)); add_compatible_session(compatible(1), compatible_pid(1)); } std::string compatible(int i) { return "compatible" + std::to_string(i); } pid_t compatible_pid(int i) { return rt::default_pid + 100 + i; } std::string incompatible(int i) { return "incompatible" + std::to_string(i); } pid_t incompatible_pid(int i) { return rt::default_pid + 200 + i; } }; } TEST_F(ASession, switch_to_incompatible_session_disables_inactivity_timeouts) { turn_on_display(); switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(ASession, removal_disables_inactivity_timeouts) { turn_on_display(); remove_session(default_session_id); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(ASession, switch_to_known_compatible_session_turns_on_display_with_normal_timeout) { expect_no_display_power_change(); switch_to_session(incompatible(0)); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_on(); switch_to_session(default_session_id); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); } TEST_F(ASession, switch_to_session_without_active_call_disables_proximity) { emit_active_call(); switch_to_session(compatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); } TEST_F(ASession, removal_disables_proximity) { emit_active_call(); remove_session(default_session_id); EXPECT_FALSE(are_proximity_events_enabled()); } TEST_F(ASession, switch_back_to_session_with_active_call_reenables_proximity) { auto const without_call = 0; emit_active_call(); switch_to_session(compatible(without_call)); switch_to_session(default_session_id); expect_display_turns_off(); emit_proximity_state_near_if_enabled(); } TEST_F(ASession, switch_back_to_sessions_with_call_finished_while_inactive_does_not_reenable_proximity) { auto const with_initially_active_call = 0; auto const another_with_initially_active_call = 1; switch_to_session(compatible(with_initially_active_call)); emit_active_call(); switch_to_session(compatible(another_with_initially_active_call)); emit_active_call(); switch_to_session(default_session_id); emit_no_active_call(); switch_to_session(compatible(with_initially_active_call)); expect_no_display_power_change(); expect_no_display_brightness_change(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); verify_expectations(); switch_to_session(compatible(another_with_initially_active_call)); expect_no_display_power_change(); expect_no_display_brightness_change(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); verify_expectations(); } TEST_F(ASession, switch_to_incompatible_session_disables_autobrightness) { expect_autobrightness_disabled(); switch_to_session(incompatible(0)); } TEST_F(ASession, removal_disables_autobrightness) { expect_autobrightness_disabled(); remove_session(default_session_id); } TEST_F(ASession, while_inactive_does_not_change_display_for_inactivity_timeout_requests_if_display_is_off) { switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); client_request_disable_inactivity_timeout(); client_request_enable_inactivity_timeout(); client_request_set_inactivity_timeout(10s); advance_time_by(1000s); } TEST_F(ASession, while_inactive_does_not_change_display_for_inactivity_timeout_requests_if_display_is_on) { turn_on_display(); switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); client_request_disable_inactivity_timeout(); client_request_enable_inactivity_timeout(); client_request_set_inactivity_timeout(10s); advance_time_by(1000s); } TEST_F(ASession, while_inactive_tracks_inactivity_timeout_requests) { switch_to_session(incompatible(0)); auto const timeout = 1000s; client_request_disable_inactivity_timeout("id"); client_request_set_inactivity_timeout(timeout); switch_to_session(default_session_id); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(timeout); client_request_enable_inactivity_timeout("id"); verify_expectations(); expect_display_dims(); advance_time_by(timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(ASession, while_inactive_tracks_inactivity_timeout_requests_1) { switch_to_session(incompatible(0)); auto const timeout = 1000s; client_request_disable_inactivity_timeout("id"); client_request_set_inactivity_timeout(timeout); client_request_enable_inactivity_timeout("id"); switch_to_session(default_session_id); expect_display_turns_off(); advance_time_by(timeout); } TEST_F(ASession, while_inactive_does_not_change_display_for_brightness_requests_if_display_was_off) { switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); expect_no_autobrightness_change(); client_request_set_normal_brightness_value(0.66); client_request_enable_autobrightness(); client_request_disable_autobrightness(); } TEST_F(ASession, while_inactive_does_not_change_display_for_brightness_requests_if_display_was_on) { turn_on_display(); switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); expect_no_autobrightness_change(); client_request_set_normal_brightness_value(0.66); client_request_enable_autobrightness(); client_request_disable_autobrightness(); } TEST_F(ASession, while_inactive_tracks_brightness_requests) { switch_to_session(incompatible(0)); client_request_set_normal_brightness_value(0.66); client_request_enable_autobrightness(); client_request_disable_autobrightness(); expect_autobrightness_disabled(); expect_normal_brightness_value_set_to(0.66); switch_to_session(default_session_id); } TEST_F(ASession, while_inactive_does_not_change_display_for_notification_if_display_is_on) { turn_on_display(); switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); emit_notification(); emit_notification_done(); } TEST_F(ASession, while_inactive_does_not_change_display_for_notification_if_display_is_off) { switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); emit_notification(); emit_notification_done(); } TEST_F(ASession, while_inactive_does_not_change_display_for_notification_expiration) { emit_notification(); switch_to_session(incompatible(0)); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(notification_expiration_timeout); } TEST_F(ASession, while_inactive_tracks_notification_expiration) { emit_notification(); switch_to_session(incompatible(0)); advance_time_by(notification_expiration_timeout); switch_to_session(default_session_id); expect_display_turns_off(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(ASession, while_inactive_does_not_track_power_button_long_press) { press_power_button(); switch_to_session(incompatible(0)); switch_to_session(default_session_id); expect_no_long_press_notification(); advance_time_by(power_button_long_press_timeout); } TEST_F(ASession, while_inactive_does_not_change_power_for_inactivity_timeout) { turn_on_display(); switch_to_session(incompatible(0)); expect_no_system_power_change(); advance_time_by(1000s); } TEST_F(ASession, while_inactive_does_not_change_power_if_client_reallows_suspend) { turn_on_display(); client_request_disallow_suspend(); switch_to_session(incompatible(0)); expect_no_system_power_change(); client_request_allow_suspend(); advance_time_by(1000s); } TEST_F(ASession, switch_to_incompatible_session_allows_default_system_handlers_for_power) { EXPECT_FALSE(are_default_system_handlers_allowed()); switch_to_session(incompatible(0)); EXPECT_TRUE(are_default_system_handlers_allowed()); } TEST_F(ASession, switch_to_compatible_session_disallows_default_system_handlers_for_power) { EXPECT_FALSE(are_default_system_handlers_allowed()); switch_to_session(compatible(0)); EXPECT_FALSE(are_default_system_handlers_allowed()); switch_to_session(incompatible(0)); switch_to_session(compatible(0)); EXPECT_FALSE(are_default_system_handlers_allowed()); } TEST_F(ASession, start_is_logged_if_compatible) { EXPECT_TRUE(log_contains_line({default_session_id, "start"})); switch_to_session(compatible(0)); switch_to_session(incompatible(0)); EXPECT_FALSE(log_contains_line({incompatible(0), "start"})); EXPECT_TRUE(log_contains_line({compatible(0), "start"})); } repowerd-2023.07/tests/core-tests/test_system_power_control.cpp000066400000000000000000000120471446034100200250110ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "fake_system_power_control.h" #include namespace rt = repowerd::test; using namespace std::chrono_literals; using namespace testing; namespace { struct ASystemPowerControl : rt::AcceptanceTest { void expect_automatic_suspend_is_allowed() { EXPECT_TRUE(config.the_fake_system_power_control()->is_automatic_suspend_allowed()); } void expect_automatic_suspend_is_disallowed() { EXPECT_FALSE(config.the_fake_system_power_control()->is_automatic_suspend_allowed()); } void expect_automatic_suspend_disallow() { EXPECT_CALL(config.the_fake_system_power_control()->mock, disallow_automatic_suspend(_)); } void emit_system_resume() { config.the_fake_system_power_control()->emit_system_resume(); daemon.flush(); } std::chrono::milliseconds const suspend_timeout{ user_inactivity_normal_suspend_timeout + 10s}; }; } TEST_F(ASystemPowerControl, automatic_suspend_is_disallowed_when_display_turns_on) { expect_automatic_suspend_is_allowed(); turn_on_display(); expect_automatic_suspend_is_disallowed(); } TEST_F(ASystemPowerControl, automatic_suspend_is_allowed_when_display_turns_off) { turn_on_display(); turn_off_display(); advance_time_by(std::chrono::milliseconds{4000}); expect_automatic_suspend_is_allowed(); } TEST_F(ASystemPowerControl, automatic_suspend_is_disallowed_when_display_turns_off_due_to_proximity) { turn_on_display(); emit_proximity_state_near(); expect_automatic_suspend_is_disallowed(); } TEST_F(ASystemPowerControl, suspend_inhibition_is_respected_for_automatic_suspend_due_to_inactivity) { turn_on_display(); client_request_disallow_suspend(); advance_time_by(user_inactivity_normal_display_off_timeout); expect_automatic_suspend_is_disallowed(); } TEST_F(ASystemPowerControl, suspend_inhibition_is_respected_for_automatic_suspend_due_to_power_key) { turn_on_display(); client_request_disallow_suspend(); press_power_button(); release_power_button(); expect_automatic_suspend_is_disallowed(); } TEST_F(ASystemPowerControl, removal_of_suspend_inhibition_is_respected_for_automatic_suspend_due_to_inactivity) { turn_on_display(); client_request_disallow_suspend(); press_power_button(); release_power_button(); client_request_allow_suspend(); advance_time_by(std::chrono::milliseconds{4000}); expect_automatic_suspend_is_allowed(); } TEST_F(ASystemPowerControl, removal_of_suspend_inhibition_is_respected_for_automatic_suspend_due_to_power_key) { turn_on_display(); client_request_disallow_suspend(); advance_time_by(user_inactivity_normal_display_off_timeout); client_request_allow_suspend(); advance_time_by(std::chrono::milliseconds{4000}); expect_automatic_suspend_is_allowed(); } TEST_F(ASystemPowerControl, removal_of_suspend_inhibition_has_no_effect_for_automatic_suspend_due_to_proximity) { turn_on_display(); client_request_disallow_suspend(); emit_proximity_state_near(); client_request_allow_suspend(); expect_automatic_suspend_is_disallowed(); } TEST_F(ASystemPowerControl, automatic_suspend_is_disallowed_before_display_is_turned_on) { testing::InSequence s; expect_automatic_suspend_disallow(); expect_display_turns_on(); press_power_button(); release_power_button(); } TEST_F(ASystemPowerControl, suspend_inhibit_disallow_automatic_suspend_by_itself) { testing::InSequence s; expect_automatic_suspend_is_allowed(); client_request_disallow_suspend(); expect_automatic_suspend_is_disallowed(); } TEST_F(ASystemPowerControl, system_disallow_suspend_inhibits_suspend_due_to_inactivity) { turn_on_display(); client_setting_set_inactivity_behavior( repowerd::PowerAction::suspend, repowerd::PowerSupply::battery, suspend_timeout); emit_system_disallow_suspend(); expect_no_system_power_change(); advance_time_by(suspend_timeout); expect_system_suspends(); emit_system_allow_suspend(); } TEST_F(ASystemPowerControl, resume_turns_on_screen) { expect_display_turns_on(); emit_system_resume(); } TEST_F(ASystemPowerControl, resume_is_logged) { emit_system_resume(); EXPECT_TRUE(log_contains_line({"system_resume"})); } repowerd-2023.07/tests/core-tests/test_treat_power_button_as_user_activity.cpp000066400000000000000000000071531446034100200300760ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "daemon_config.h" #include "acceptance_test.h" #include "fake_state_machine_options.h" #include "fake_shared.h" #include namespace rt = repowerd::test; using namespace testing; using namespace std::chrono_literals; namespace { struct StateMachineOptionsWithChangeDisplayState : rt::FakeStateMachineOptions { bool treat_power_button_as_user_activity() const override { return treat_power_button_as_user_activity_; }; void set_treat_power_button_as_user_activity(bool b) { treat_power_button_as_user_activity_ = b; } bool treat_power_button_as_user_activity_ = true; }; struct DaemonConfigWithChangeDisplayState : rt::DaemonConfig { std::shared_ptr the_state_machine_options() override { if (!state_machine_options) { state_machine_options = std::make_shared(); } return state_machine_options; } std::shared_ptr state_machine_options; }; } TEST(ATreatPowerButtonAsUserActivityOption, if_enabled_treats_power_button_as_user_activity) { DaemonConfigWithChangeDisplayState config; config.the_state_machine_options(); config.state_machine_options->set_treat_power_button_as_user_activity(true); rt::AcceptanceTestBase test{rt::fake_shared(config)}; test.run_daemon(); test.expect_display_turns_on(); test.press_power_button(); test.release_power_button(); test.verify_expectations(); test.expect_no_display_power_change(); test.press_power_button(); test.release_power_button(); test.advance_time_by(test.user_inactivity_normal_display_off_timeout - 1ms); test.verify_expectations(); test.expect_display_turns_off(); test.advance_time_by(1ms); } TEST(ATreatPowerButtonAsUserActivityOption, if_enabled_ignores_proximity_when_turning_display_on) { DaemonConfigWithChangeDisplayState config; config.the_state_machine_options(); config.state_machine_options->set_treat_power_button_as_user_activity(true); rt::AcceptanceTestBase test{rt::fake_shared(config)}; test.run_daemon(); test.set_proximity_state_near(); test.expect_display_turns_on(); test.press_power_button(); test.release_power_button(); } TEST(ATreatPowerButtonAsUserActivityOption, if_disabled_does_not_treat_power_button_as_user_activity) { DaemonConfigWithChangeDisplayState config; config.the_state_machine_options(); config.state_machine_options->set_treat_power_button_as_user_activity(false); rt::AcceptanceTestBase test{rt::fake_shared(config)}; test.run_daemon(); test.expect_display_turns_on(); test.press_power_button(); test.release_power_button(); test.verify_expectations(); test.expect_display_turns_off(); test.press_power_button(); test.release_power_button(); } repowerd-2023.07/tests/core-tests/test_turn_on_display_at_startup.cpp000066400000000000000000000046761446034100200262010ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "daemon_config.h" #include "fake_state_machine_options.h" #include "fake_shared.h" #include namespace rt = repowerd::test; namespace { struct StateMachineOptionsWithTurnOnDisplayAtStartup : rt::FakeStateMachineOptions { bool turn_on_display_at_startup() const override { return turn_on_display_at_startup_; }; void set_turn_on_display_at_startup(bool b) { turn_on_display_at_startup_ = b; } bool turn_on_display_at_startup_ = true; }; struct DaemonConfigWithTurnOnDisplayAtStartup : rt::DaemonConfig { std::shared_ptr the_state_machine_options() override { if (!state_machine_options) { state_machine_options = std::make_shared(); } return state_machine_options; } std::shared_ptr state_machine_options; }; struct ATurnOnDisplayAtStartupOption : testing::Test { DaemonConfigWithTurnOnDisplayAtStartup config; }; } TEST_F(ATurnOnDisplayAtStartupOption, if_enabled_turns_on_display_at_startup) { config.the_state_machine_options(); config.state_machine_options->set_turn_on_display_at_startup(true); rt::AcceptanceTestBase test{rt::fake_shared(config)}; test.expect_display_turns_on(); test.run_daemon(); } TEST_F(ATurnOnDisplayAtStartupOption, if_disabled_does_not_turn_on_display_at_startup) { config.the_state_machine_options(); config.state_machine_options->set_turn_on_display_at_startup(false); rt::AcceptanceTestBase test{rt::fake_shared(config)}; test.expect_no_display_power_change(); test.expect_no_display_brightness_change(); test.run_daemon(); } repowerd-2023.07/tests/core-tests/test_user_activity.cpp000066400000000000000000000137671446034100200234150ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct AUserActivity : rt::AcceptanceTest { }; } TEST_F(AUserActivity, not_performed_turns_off_display_after_timeout) { turn_on_display(); expect_display_turns_off(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(AUserActivity, not_performed_dims_display_after_timeout_timeout) { turn_on_display(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_dim_timeout); } TEST_F(AUserActivity, not_performed_does_not_turn_off_display_prematurely) { turn_on_display(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); } TEST_F(AUserActivity, not_performed_does_not_dim_display_prematurely) { turn_on_display(); expect_no_display_brightness_change(); advance_time_by(user_inactivity_normal_display_dim_timeout - 1ms); } TEST_F(AUserActivity, not_performed_has_no_effect_after_display_is_turned_off) { turn_on_display(); turn_off_display(); expect_no_display_brightness_change(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(AUserActivity, extending_power_state_has_no_effect_when_display_is_off) { expect_no_display_brightness_change(); expect_no_display_power_change(); perform_user_activity_extending_power_state(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(AUserActivity, extending_power_state_resets_display_off_timer) { turn_on_display(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); perform_user_activity_extending_power_state(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AUserActivity, extending_power_state_brightens_dim_display) { turn_on_display(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_brightens(); perform_user_activity_extending_power_state(); } TEST_F(AUserActivity, changing_power_state_turns_on_display_immediately) { expect_display_turns_on(); perform_user_activity_changing_power_state(); } TEST_F(AUserActivity, changing_power_state_does_not_turn_on_display_if_it_is_already_on) { turn_on_display(); expect_no_display_power_change(); perform_user_activity_changing_power_state(); } TEST_F(AUserActivity, changing_power_state_resets_display_off_timer) { turn_on_display(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); perform_user_activity_changing_power_state(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AUserActivity, changing_power_state_brightens_dim_display) { turn_on_display(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_brightens(); perform_user_activity_changing_power_state(); } TEST_F(AUserActivity, event_notifies_of_display_power_change) { expect_display_power_on_notification( repowerd::DisplayPowerChangeReason::activity); perform_user_activity_changing_power_state(); verify_expectations(); expect_display_power_off_notification( repowerd::DisplayPowerChangeReason::activity); advance_time_by(user_inactivity_normal_display_off_timeout); verify_expectations(); } TEST_F(AUserActivity, changing_power_state_keeps_screen_on_forever_if_inactivity_timeout_is_infinite) { client_request_set_inactivity_timeout(infinite_timeout); emit_notification(); emit_notification_done(); perform_user_activity_changing_power_state(); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(1h); } TEST_F(AUserActivity, extending_power_state_keeps_screen_on_forever_if_inactivity_timeout_is_infinite) { client_request_set_inactivity_timeout(infinite_timeout); emit_notification(); emit_notification_done(); perform_user_activity_extending_power_state(); expect_no_display_power_change(); expect_no_display_brightness_change(); advance_time_by(1h); } TEST_F(AUserActivity, extending_power_state_is_logged) { perform_user_activity_extending_power_state(); EXPECT_TRUE(log_contains_line({"user_activity", "extending_power_state"})); } TEST_F(AUserActivity, changing_power_state_is_logged) { perform_user_activity_changing_power_state(); EXPECT_TRUE(log_contains_line({"user_activity", "changing_power_state"})); } TEST_F(AUserActivity, not_performed_turning_off_display_is_logged) { turn_on_display(); advance_time_by(user_inactivity_normal_display_dim_timeout); EXPECT_TRUE(log_contains_line({"display_dim"})); EXPECT_FALSE(log_contains_line({"display_off"})); advance_time_by( user_inactivity_normal_display_off_timeout - user_inactivity_normal_display_dim_timeout); EXPECT_TRUE(log_contains_line({"display_off"})); } repowerd-2023.07/tests/core-tests/test_voice_call.cpp000066400000000000000000000147331446034100200226150ustar00rootroot00000000000000/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "acceptance_test.h" #include "fake_proximity_sensor.h" #include #include namespace rt = repowerd::test; using namespace std::chrono_literals; namespace { struct AVoiceCall : rt::AcceptanceTest { }; } TEST_F(AVoiceCall, turns_on_display_with_normal_timeout) { expect_display_turns_on(); emit_active_call(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AVoiceCall, brightens_display_if_it_is_already_on) { turn_on_display(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_no_display_power_change(); expect_display_brightens(); emit_active_call(); } TEST_F(AVoiceCall, extends_timeout_if_display_is_already_on) { turn_on_display(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); expect_no_display_power_change(); emit_active_call(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AVoiceCall, enables_proximity_events) { emit_active_call(); expect_display_turns_off(); emit_proximity_state_near_if_enabled(); verify_expectations(); expect_display_turns_on(); emit_proximity_state_far_if_enabled(); verify_expectations(); } TEST_F(AVoiceCall, when_done_turns_off_display_with_reduced_timeout) { emit_active_call(); advance_time_by(user_inactivity_normal_display_off_timeout); expect_display_turns_on(); emit_no_active_call(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_reduced_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AVoiceCall, when_done_brightens_display_if_it_is_already_on) { emit_active_call(); expect_display_dims(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_no_display_power_change(); expect_display_brightens(); emit_no_active_call(); } TEST_F(AVoiceCall, when_done_extends_timeout_if_display_is_already_on) { emit_active_call(); expect_no_display_power_change(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); emit_no_active_call(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_reduced_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AVoiceCall, when_done_disables_proximity_events) { emit_active_call(); emit_no_active_call(); expect_no_display_power_change(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); verify_expectations(); } TEST_F(AVoiceCall, when_done_turns_off_screen_if_client_has_disabled_inactivity_timeout_and_display_was_off) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); turn_off_display(); expect_display_turns_on(); emit_active_call(); expect_display_brightens(); emit_no_active_call(); verify_expectations(); expect_display_turns_off(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(AVoiceCall, when_done_does_not_turn_off_display_if_a_client_has_disabled_inactivity_timeout_and_the_display_was_on) { expect_display_turns_on(); client_request_disable_inactivity_timeout(); verify_expectations(); expect_no_display_power_change(); emit_active_call(); emit_no_active_call(); advance_time_by(user_inactivity_normal_display_off_timeout); } TEST_F(AVoiceCall, when_done_enables_one_off_proximity_far_event_if_display_is_off) { turn_on_display(); expect_display_turns_off(); emit_active_call(); emit_proximity_state_near_if_enabled(); emit_no_active_call(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_reduced_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_on(); emit_proximity_state_far_if_enabled(); verify_expectations(); expect_no_display_power_change(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); advance_time_by(user_inactivity_normal_display_off_timeout - 1ms); verify_expectations(); expect_display_turns_off(); advance_time_by(1ms); } TEST_F(AVoiceCall, when_done_enables_one_off_proximity_far_event_if_display_is_off_which_expires_after_reduced_timeout) { turn_on_display(); expect_display_turns_off(); emit_active_call(); emit_proximity_state_near_if_enabled(); emit_no_active_call(); verify_expectations(); expect_no_display_power_change(); advance_time_by(user_inactivity_reduced_display_off_timeout); emit_proximity_state_far_if_enabled(); emit_proximity_state_near_if_enabled(); emit_proximity_state_far_if_enabled(); } TEST_F(AVoiceCall, event_notifies_of_display_power_change) { expect_display_power_on_notification( repowerd::DisplayPowerChangeReason::call); emit_active_call(); verify_expectations(); turn_off_display(); expect_display_power_on_notification( repowerd::DisplayPowerChangeReason::call_done); emit_no_active_call(); verify_expectations(); } TEST_F(AVoiceCall, is_logged) { emit_active_call(); EXPECT_TRUE(log_contains_line({"active_call"})); } TEST_F(AVoiceCall, done_is_logged) { emit_active_call(); emit_no_active_call(); EXPECT_TRUE(log_contains_line({"no_active_call"})); }