battery: introduce battery-plugin for iot-headless 23/268823/8
authorYoungjae Cho <y0.cho@samsung.com>
Mon, 3 Jan 2022 09:35:05 +0000 (18:35 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Fri, 7 Jan 2022 04:39:53 +0000 (13:39 +0900)
It handles battery event according to the iot-headless policy. Those
policies are specified in battery.conf. For now it only handles event
about charger connect/disconnect.
 1. It triggers power state transition. Those transition actions are
    specified in EVENT_ACTION section.
 2. It might hold wakelock for charger connection. It is specified in
    CHARGER_WAKELOCK section.

Change-Id: Iee6803604a25bacca5ce68953033b71560ed4ba8
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
CMakeLists.txt
conf/battery.conf
packaging/deviced.spec
plugins/iot-headless/battery/CMakeLists.txt [new file with mode: 0644]
plugins/iot-headless/battery/battery-plugin.c [new file with mode: 0644]
plugins/iot-headless/input/input-config.c
plugins/iot-headless/power/power-event-lock.c
plugins/iot-headless/power/power-state-manager.c
src/battery/power-supply.c
src/shared/device-notifier.h

index 4a47b81..96d3312 100644 (file)
@@ -333,6 +333,7 @@ ADD_SUBDIRECTORY(plugins/tv/display)
 ADD_SUBDIRECTORY(plugins/iot-headed/display)
 ADD_SUBDIRECTORY(plugins/iot-headless/input)
 ADD_SUBDIRECTORY(plugins/iot-headless/power)
+ADD_SUBDIRECTORY(plugins/iot-headless/battery)
 IF(BATTERY_MODULE STREQUAL on)
        ADD_SUBDIRECTORY(plugins/mobile/battery)
        ADD_SUBDIRECTORY(plugins/wearable/battery)
index c882320..b376658 100644 (file)
@@ -7,3 +7,26 @@ PowerOff=1
 RealOff=0
 WarningMethod=warning
 CriticalMethod=critical
+
+# hold wakelock if a charger has been connected, iot-headless only
+[CHARGER_WAKELOCK]
+ChargerWakeLockEnabled=yes
+
+# define event-action, iot-headless only
+# DeviceNotifier=
+#  - define which event(device-notifiy) is filtered
+#  Action=
+#  - define action for the event
+[EVENT_ACTION]
+Name=CHARGER_CONNECTED
+Enum=2001
+DeviceNotifier=DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED
+Action=sleep,sleep
+Action=normal,normal
+
+[EVENT_ACTION]
+Name=CHARGER_DISCONNECTED
+Enum=2002
+DeviceNotifier=DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED
+Action=sleep,sleep
+Action=normal,normal
index 7adeb77..e32051c 100644 (file)
@@ -252,6 +252,7 @@ mv %{_sysconfdir}/deviced/iot-headless-input.conf %{_sysconfdir}/deviced/input.c
 mkdir -p %{_libdir}/deviced
 mv %{_libdir}/iot-headless-input-handler.so %{_libdir}/deviced/input-handler.so
 mv %{_libdir}/iot-headless-power.so %{_libdir}/deviced/power.so
+mv %{_libdir}/iot-headless-battery.so %{_libdir}/deviced/battery.so
 
 %files
 %manifest %{name}.manifest
@@ -375,5 +376,6 @@ mv %{_libdir}/iot-headless-power.so %{_libdir}/deviced/power.so
 %config %{_sysconfdir}/deviced/iot-headless-input.conf
 %{_libdir}/iot-headless-input-handler.so
 %{_libdir}/iot-headless-power.so
+%{_libdir}/iot-headless-battery.so
 %{_unitdir}/rndis.service
 %{_bindir}/rndis.sh
diff --git a/plugins/iot-headless/battery/CMakeLists.txt b/plugins/iot-headless/battery/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a9ab36c
--- /dev/null
@@ -0,0 +1,18 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT(iot-headless-battery C)
+
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(REQUIRED_PKGS REQUIRED
+       glib-2.0
+       dlog
+       libsyscommon)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../power)
+
+FILE(GLOB SRCS "*.c")
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "")
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME iot-headless-battery)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
diff --git a/plugins/iot-headless/battery/battery-plugin.c b/plugins/iot-headless/battery/battery-plugin.c
new file mode 100644 (file)
index 0000000..e0b2bbd
--- /dev/null
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <glib.h>
+#include <libsyscommon/ini-parser.h>
+#include <libsyscommon/list.h>
+
+#include "shared/device-notifier.h"
+#include "shared/log.h"
+#include "battery/battery-ops.h"
+
+#include "power-state-manager.h"
+
+#define BATTERY_CONF_PATH    "/etc/deviced/battery.conf"
+
+struct battery_event_handler {
+       char *name;
+       int id;
+
+       /* which action to do on receiving an event */
+       enum device_notifier_type action;
+       void *user_data;
+};
+
+static struct battery_event_handler *handler_connected;
+static struct battery_event_handler *handler_disconnected;
+
+static void parse_device_notifier(struct battery_event_handler *handler, const char *action)
+{
+       if (MATCH(action, "DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED")) {
+               handler_connected = handler;
+       } else if (MATCH(action, "DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED")) {
+               handler_disconnected = handler;
+       }
+}
+
+static enum psm_state convert_action_string_to_psm_state(char *str)
+{
+       if (MATCH(str, "sleep"))
+               return PSM_SLEEP;
+       else if (MATCH(str, "normal"))
+               return PSM_NORMAL;
+       else if (MATCH(str, "poweroff"))
+               return PSM_POWEROFF;
+
+       _W("Invalid psm_state=%s", str);
+
+       return PSM_MAX;
+}
+
+static void add_action_transition_info(struct battery_event_handler *handler, char *curr, char *next)
+{
+       struct trans_info *ti = NULL;
+       GList **action_list = (GList **) &(handler->user_data);
+
+       ti = calloc(1, sizeof(struct trans_info));
+       if (!ti)
+               return;
+
+       /* In configuration file, Enum= must be followed by Action=.
+        * Otherwise, handler->id won't be defined at this point.*/
+       ti->reason = handler->id;
+
+       ti->curr = convert_action_string_to_psm_state(curr);
+       ti->next = convert_action_string_to_psm_state(next);
+
+       SYS_G_LIST_APPEND(*action_list, ti);
+}
+
+static void parse_action(struct battery_event_handler *handler, const char *action)
+{
+       char curr[16] = { 0, };
+       char next[16] = { 0, };
+
+       if (sscanf(action, "%15[^,],%15s", curr, next) == 2) {
+               handler->action = DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE;
+               /* append transition info to handler->user_data */
+               add_action_transition_info(handler, curr, next);
+       } else {
+               _E("Invalid action=%s", action);
+       }
+}
+
+static void parse_event_action_property(gpointer data, gpointer user_data)
+{
+       struct section_property *prop = (struct section_property *) data;
+       struct battery_event_handler *handler = (struct battery_event_handler *) user_data;
+
+       if (!prop)
+               return;
+
+       _D("Key=%s, Value=%s", prop->key, prop->value);
+
+       if (MATCH(prop->key, "Name")) {
+               handler->name = strndup(prop->value, 32);
+       } else if (MATCH(prop->key, "Enum")) {
+               sscanf(prop->value, "%d", &handler->id);
+       } else if (MATCH(prop->key, "DeviceNotifier")) {
+               parse_device_notifier(handler, prop->value);
+       } else if (MATCH(prop->key, "Action")) {
+               parse_action(handler, prop->value);
+       }
+}
+
+static int parse_event_action(const struct parse_result *result, void *data)
+{
+       struct battery_event_handler *handler = NULL;
+
+       if (!result || !result->props)
+               return 0;
+
+       if (MATCH(result->section, "EVENT_ACTION")) {
+               handler = calloc(1, sizeof(struct battery_event_handler));
+               if (!handler)
+                       return 0;
+
+               g_list_foreach(result->props, parse_event_action_property, handler);
+       }
+
+       return 0;
+}
+
+static int charger_connected_callback(void *data)
+{
+       _D("event=%s(%d), action=%d", handler_connected->name, handler_connected->id, handler_connected->action);
+       device_notify(handler_connected->action, handler_connected->user_data);
+
+       return 0;
+}
+
+static int charger_disconnected_callback(void *data)
+{
+       _D("event=%s(%d), action=%d", handler_disconnected->name, handler_disconnected->id, handler_disconnected->action);
+       device_notify(handler_disconnected->action, handler_disconnected->user_data);
+
+       return 0;
+}
+
+static void battery_plugin_init(void *data)
+{
+       libsys_config_parse_by_section(BATTERY_CONF_PATH, parse_event_action, NULL);
+
+       if (handler_connected)
+               register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, charger_connected_callback);
+
+       if (handler_disconnected)
+               register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, charger_disconnected_callback);
+}
+
+static const struct battery_ops battery_plugin_ops = {
+       .name     = "battery-plugin",
+       .init     = battery_plugin_init,
+};
+
+BATTERY_OPS_REGISTER(&battery_plugin_ops)
index 026c7be..ce798cd 100644 (file)
@@ -112,7 +112,7 @@ static void parse_action(struct input_event_unit *ieu, const char *action)
                ieu->notifier = DEVICE_NOTIFIER_INPUT_BROADCAST_SIGNAL;
                ieu->user_data = (void *) ieu;
        } else if (sscanf(action, "%15[^,],%15s", curr, next) == 2) {
-               ieu->notifier = DEVICE_NOTIFIER_INPUT_TRANSITION_STATE;
+               ieu->notifier = DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE;
                /* append transition info to ieu->user_data */
                add_action_transition_info(ieu, curr, next);
        } else {
index 0e75814..2e41d6e 100644 (file)
@@ -1,19 +1,21 @@
 #include <glib.h>
 #include <stdint.h>
 #include <linux/input.h>
+#include <libsyscommon/ini-parser.h>
 
 #include "shared/bitmap.h"
 #include "shared/device-notifier.h"
 #include "shared/log.h"
 #include "power-event-lock.h"
 
+#define BATTERY_CONF_FILE    "/etc/deviced/battery.conf"
+
 /* eventlock is another wakelock than mainlock.
  *
  * The eventlock works independently of mainlock, which is controlled by
  * power state. The main purpose of eventlock is to prevent the subroutine
  * of an event from going to sleep regardless of the power state. */
-#define EVENT_LOCK              "eventlock"
-#define EVENT_LOCK_MARGIN_MS    1000
+#define EVENT_LOCK           "eventlock"
 
 enum eventlock_type {
        EL_MIN,
@@ -21,6 +23,8 @@ enum eventlock_type {
        EL_KEY,
        EL_KEY_POWER = EL_KEY,
        EL_KEY_BLUETOOTH,
+
+       EL_CHARGER,
        /* add eventlock type here */
        EL_MAX,
 };
@@ -119,15 +123,35 @@ static void register_power_event_lock_controller(enum eventlock_type type,
                power_event_unlock_callback, (void *)(intptr_t) type, NULL, -1000);
 }
 
+static int check_charger_wakelock(struct parse_result *result, void *user_data)
+{
+       if (MATCH(result->section, "CHARGER_WAKELOCK")
+               && MATCH(result->name, "ChargerWakeLockEnabled")
+               && MATCH(result->value, "yes"))
+               *(int *) user_data = 1;
+
+       return 0;
+}
+
 void power_event_lock_init(void)
 {
+       int charger_wakelock = 0;
+
        eventlock = init_bitmap(EL_MAX);
        if (!eventlock) {
                _E("Failed to init event lock bitmap");
                return;
        }
 
+       config_parse(BATTERY_CONF_FILE, check_charger_wakelock, &charger_wakelock);
+
        register_power_event_lock_controller(EL_KEY,
                DEVICE_NOTIFIER_KEY_PRESS,
                DEVICE_NOTIFIER_KEY_RELEASE);
+
+       if (charger_wakelock) {
+               register_power_event_lock_controller(EL_CHARGER,
+                       DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED,
+                       DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED);
+       }
 }
index 5232c20..b50fd78 100644 (file)
@@ -186,7 +186,7 @@ void power_state_manager_init(void *data)
        device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL);
        device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
 
-       register_notifier(DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, psm_transition_state_cb);
+       register_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, psm_transition_state_cb);
 
        power_plugin_dbus_init(NULL);
        power_event_lock_init();
index 12f263a..e886782 100644 (file)
@@ -405,26 +405,25 @@ static void charger_state_send_system_event(int state)
                break;
        case CHARGE_STATUS_FULL:
                str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
-               CRITICAL_LOG("Battery %s", str);
+               CRITICAL_LOG("Battery charger: %s", str);
                break;
        case CHARGE_STATUS_DISCHARGING:
                str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
+               CRITICAL_LOG("Battery charger: %s", str);
                break;
        case CHARGE_STATUS_CONNECTED:
                str = EVT_VAL_BATTERY_CHARGER_CONNECTED;
-               CRITICAL_LOG("Battery %s", str);
+               CRITICAL_LOG("Battery charger: %s", str);
                break;
        case CHARGE_STATUS_DISCONNECTED:
                str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED;
-               CRITICAL_LOG("Battery %s", str);
+               CRITICAL_LOG("Battery charger: %s", str);
                break;
        default:
                _E("Invalid parameter: %d", state);
                return;
        }
 
-       _D("System_event: %s", str);
-
        event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
 }
 
@@ -577,6 +576,7 @@ static bool update_online(void)
                extcon_update_count(EXTCON_TA, 1);
                check_power_supply(online_status);
                charger_state_send_system_event(CHARGE_STATUS_CONNECTED);
+               device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, NULL);
                if (old_battery.charge_status != battery.charge_status)
                        charger_state_send_system_event(battery.charge_status);
                broadcast = true;
@@ -587,6 +587,7 @@ static bool update_online(void)
                if (old_battery.charge_status != battery.charge_status)
                        charger_state_send_system_event(battery.charge_status);
                charger_state_send_system_event(CHARGE_STATUS_DISCONNECTED);
+               device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, NULL);
                broadcast = true;
        } else {
                if (old_battery.charge_status != battery.charge_status)
index 241b339..6ccae1a 100644 (file)
@@ -34,6 +34,8 @@ enum device_notifier_type {
        DEVICE_NOTIFIER_BATTERY_PRESENT,
        DEVICE_NOTIFIER_BATTERY_OVP,
        DEVICE_NOTIFIER_BATTERY_CHARGING,
+       DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED,
+       DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED,
        DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION,
        DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE,
        DEVICE_NOTIFIER_DISPLAY_LOCK,
@@ -66,8 +68,6 @@ enum device_notifier_type {
        /* action triggered by input event */
        DEVICE_NOTIFIER_INPUT_TRIGGER_POWEROFF,
        DEVICE_NOTIFIER_INPUT_BROADCAST_SIGNAL,
-       DEVICE_NOTIFIER_INPUT_TRANSITION_STATE,
-
 
        /* Purpose of calling methods of different modules
         * Use prefix DEVICE_NOTIFIER_REQUEST */
@@ -75,6 +75,7 @@ enum device_notifier_type {
        DEVICE_NOTIFIER_REQUEST_DISABLE_AUTOSLEEP,
        DEVICE_NOTIFIER_REQUEST_WAKE_LOCK,
        DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK,
+       DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE,
        DEVICE_NOTIFIER_MAX,
 };