#include <hw/thermal.h>
#include <libgdbus/dbus-system.h>
+#include <vconf.h>
#include "apps/apps.h"
#include "core/devices.h"
#include "core/log.h"
#include "core/device-notifier.h"
#include "core/devices.h"
+#include "display/display-ops.h"
+#include "battery/power-supply.h"
+#include "power/power-handler.h"
#include "thermal.h"
-#include "core/config-parser.h"
static struct thermal_device *thermal_dev;
-static int noti;
+static int cool_down_level = COOL_DOWN_NONE_INIT;
+static guint shut_down_timer;
-#define THERMAL_CONF_FILE "/etc/deviced/temperature.conf"
-
-static struct thermal_config_info thermal_table = {
- .normal = TEMPERATURE_NORMAL,
- .warning = TEMPERATURE_WARNING,
- .limit = TEMPERATURE_LIMIT,
- .shutdown = TEMPERATURE_SHUTDOWN
-};
-
-static int power_off(void)
+static int booting_done(void *data)
{
- const struct device_ops *power;
+ static int done;
- power = find_device("power");
- if (check_default(power))
- return -ENODEV;
+ if (data == NULL)
+ return done;
- return power->execute("poweroff");
+ done = *(int *)data;
+ if (done == 0)
+ return done;
+
+ _I("Booting done.");
+ return done;
}
-static void thermal_remove_noti(void)
+static int get_action_id(char *string)
{
- int ret = 0;
+ int temp = COOL_DOWN_NONE_INIT;
- if (noti) {
- ret = remove_notification("TempCooldownNotiOff", noti);
- if (ret < 0)
- _E("Failed to remove cooldown noti(%d).", noti);
- else
- noti = 0;
+ if (!string) {
+ _E("Invalid temp level");
+ return temp;
}
+
+ if (!strncmp(string, RELEASE_ACTION, strlen(RELEASE_ACTION)))
+ temp = COOL_DOWN_RELEASE;
+ else if (!strncmp(string, WARNING_ACTION, strlen(WARNING_ACTION)))
+ temp = COOL_DOWN_WARNING_ACTION;
+ else if (!strncmp(string, LIMIT_ACTION, strlen(LIMIT_ACTION)))
+ temp = COOL_DOWN_LIMIT_ACTION;
+ else if (!strncmp(string, SHUTDOWN_ACTION, strlen(SHUTDOWN_ACTION)))
+ temp = COOL_DOWN_SHUT_DOWN;
+ else
+ temp = -EINVAL;
+
+ return temp;
}
-static void thermal_remove_popup(void)
+void cool_down_wakeup(int level)
{
- int temp;
-
- temp = launch_system_app(APP_DEFAULT, 2,
- APP_KEY_TYPE, "remove_cooldown_popups");
- if (temp < 0)
- _E("Failed to launch remove_cooldown_popups.");
+ if (level >= COOL_DOWN_LIMIT_ACTION || battery.health == HEALTH_BAD) {
+ _D("Dim.");
+ if (disp_plgn.pm_change_internal)
+ disp_plgn.pm_change_internal(INTERNAL_LOCK_COOL_DOWN, LCD_DIM);
+ } else {
+ _D("Normal.");
+ if (disp_plgn.pm_change_internal)
+ disp_plgn.pm_change_internal(INTERNAL_LOCK_COOL_DOWN, LCD_NORMAL);
+ }
}
-static void thermal_noti_cb(GVariant *var, void *user_data, GError *err)
+void cool_down_release(void)
{
- int id = 0;
+ device_notify(DEVICE_NOTIFIER_COOL_DOWN, (void *)&cool_down_level);
+}
- if (!var) {
- if (err)
- _E("%s", err->message);
- return;
- }
+void cool_down_warning(void)
+{
+ device_notify(DEVICE_NOTIFIER_COOL_DOWN, (void *)&cool_down_level);
+}
- if (!dh_get_param_from_var(var, "(i)", &id)) {
- _E("Failed to get var(%s): no message", g_variant_get_type_string(var));
- goto out;
+void cool_down_limit(void)
+{
+ if (disp_plgn.pm_lock_internal) {
+ disp_plgn.pm_lock_internal(INTERNAL_LOCK_COOL_DOWN, LCD_DIM, STAY_CUR_STATE, 65000);
+ disp_plgn.pm_lock_internal(INTERNAL_LOCK_COOL_DOWN, LCD_OFF, STAY_CUR_STATE, 65000);
}
- noti = id;
- _D("Thermal noti(%d).", noti);
-
-out:
- g_variant_unref(var);
+ device_notify(DEVICE_NOTIFIER_COOL_DOWN, (void *)&cool_down_level);
}
-static void thermal_add_noti(void)
+void cool_down_poweroff(void)
{
- int ret = 0;
-
- thermal_remove_noti();
- if (!noti) {
- ret = add_async_notification("TempCooldownNotiOn", thermal_noti_cb, NULL, NULL);
- if (ret < 0)
- _E("Failed to show notification for temperature.");
+ if (disp_plgn.pm_change_internal)
+ disp_plgn.pm_change_internal(INTERNAL_LOCK_COOL_DOWN, LCD_DIM);
+ if (disp_plgn.pm_lock_internal) {
+ disp_plgn.pm_lock_internal(INTERNAL_LOCK_COOL_DOWN, LCD_DIM, STAY_CUR_STATE, 30000);
+ disp_plgn.pm_lock_internal(INTERNAL_LOCK_COOL_DOWN, LCD_OFF, STAY_CUR_STATE, 30000);
}
+
+ device_notify(DEVICE_NOTIFIER_COOL_DOWN, (void *)&cool_down_level);
}
-static void broadcast_thermal_state_legacy(const char *action_type)
+static int power_execute(void *data)
{
- if (!action_type) {
- _E("Invalid action type.");
- return;
- }
+ static const struct device_ops *ops;
- _D("action_type = %s", action_type);
- dbus_handle_broadcast_dbus_signal_var(DEVICED_PATH_SYSNOTI,
- DEVICED_INTERFACE_SYSNOTI,
- "CoolDownChanged",
- g_variant_new("(s)", action_type));
+ FIND_DEVICE_INT(ops, POWER_OPS_NAME);
+
+ return ops->execute(data);
}
-static gboolean thermal_overheat_time_broadcast(void *data)
+static gboolean shut_down_timer_cb(void *data)
{
int ret;
- static int time = OVERHEAT_POWEROFF_TIME;
- /* Transfer Time by Signal */
- ret = dbus_handle_broadcast_dbus_signal_var(POPUP_OVERHEAT_PATH, POPUP_OVERHEAT_INTERFACE,
- SIGNAL_OVERHEAT_TIME, g_variant_new("(i)", time));
- if (ret < 0)
- _E("Failed in updating overheat time.");
-
- time -= 1;
- if (time < 0) {
- time = OVERHEAT_POWEROFF_TIME;
- ret = launch_system_app(APP_OVERHEAT, 2,
- APP_KEY_TYPE, "remove_overheat_popups");
- if (ret < 0)
- _E("Failed to remove overheat popups.");
-
- ret = power_off();
- if (ret < 0)
- _E("Failed to power off.");
- return G_SOURCE_REMOVE;
- } else
- return G_SOURCE_CONTINUE;
+ shut_down_timer = 0;
+ ret = power_execute(POWER_POWEROFF);
+ if (ret != 0)
+ _E("Failed to request poweroff.");
+
+ return G_SOURCE_REMOVE;
}
-static void thermal_overheat_popup(void)
+void shut_down_timer_stop(void)
{
- int ret;
- guint timer;
-
- ret = launch_system_app(APP_OVERHEAT, 2,
- APP_KEY_TYPE, "overheat");
+ if (!shut_down_timer)
+ return;
- if (ret < 0)
- _E("Failed to launch overheat popup.");
- else {
- timer = g_timeout_add_seconds(OVERHEAT_CALLBACK_TIME, thermal_overheat_time_broadcast, NULL);
- if (!timer)
- _E("Failed to set over temp timer.");
- }
+ g_source_remove(shut_down_timer);
+ shut_down_timer = 0;
+ _I("Stop cool down power off.");
}
-static void thermal_add_recovery_popup(void)
+void shut_down_timer_start(void)
{
- int temp;
+ if (shut_down_timer)
+ shut_down_timer_stop();
- temp = launch_system_app(APP_DEFAULT, 2,
- APP_KEY_TYPE, "cooled_down");
- if (temp < 0)
- _E("Failed to launch recovery popup.");
+ shut_down_timer = g_timeout_add_seconds(
+ SHUTDOWN_FORCE_WAIT,
+ shut_down_timer_cb, NULL);
}
-static void thermal_action(int state)
+static int cool_down_execute(int state)
{
- char *action = NULL;
+ int ret;
+ static int old_state = COOL_DOWN_NONE_INIT;
+
+ cool_down_level = state;
+ if (vconf_set_int(VCONFKEY_SYSMAN_COOL_DOWN_MODE, cool_down_level) != 0)
+ _E("Failed to set VCONFKEY_SYSMAN_COOL_DOWN_MODE : %d", cool_down_level);
+
+ if (old_state == cool_down_level) {
+ if (cool_down_level == COOL_DOWN_SHUT_DOWN) {
+ _I("Force cool down power off by multiple shutdown request.");
+ ret = power_execute(POWER_POWEROFF);
+ if (ret != 0)
+ _E("Failed to request poweroff.");
+ }
+ return 0;
+ }
+
+ if (!booting_done(NULL)) {
+ _E("Booting is not done.");
+ return 0;
+ }
switch (state) {
- case NORMAL:
- thermal_remove_noti();
- thermal_add_recovery_popup();
- action = strdup(RELEASE_ACTION);
+ case COOL_DOWN_RELEASE:
+ shut_down_timer_stop();
+ cool_down_release();
break;
- case WARNING:
+ case COOL_DOWN_WARNING_ACTION:
+ cool_down_warning();
_I("State is WARNING.");
- action = strdup(WARNING_ACTION);
break;
- case LIMIT:
- thermal_remove_popup();
- thermal_add_noti();
- action = strdup(LIMIT_ACTION);
+ case COOL_DOWN_LIMIT_ACTION:
+ cool_down_limit();
+ cool_down_wakeup(COOL_DOWN_LIMIT_ACTION);
break;
- case SHUTDOWN:
- thermal_remove_popup();
- thermal_remove_noti();
- thermal_overheat_popup();
- action = strdup(SHUTDOWN_ACTION);
+ case COOL_DOWN_SHUT_DOWN:
+ cool_down_wakeup(COOL_DOWN_SHUT_DOWN);
+ cool_down_poweroff();
+ shut_down_timer_start();
break;
- }
-
- broadcast_thermal_state_legacy(action);
- free(action);
-}
-/* Action Table
---------------------------------------------------
-Current Previous Action
---------------------------------------------------
-NORMAL NORMAL X
- WARNING X
- LIMIT ReleaseAction
- SHUTDOWN X
---------------------------------------------------
-WARNING NORMAL print log
- WARNING X
- LIMIT X
- SHUTDOWN X
---------------------------------------------------
-LIMIT NORMAL LimitAction
- WARNING LimitAction
- LIMIT X
- SHUTDOWN X
---------------------------------------
-SHUTDOWN NORMAL ShutdownAction
- WARNING ShutdownAction
- LIMIT ShutdownAction
- SHUTDOWN X
---------------------------------------------------
-*/
-static bool is_action_needed(int old_state, int new_state)
-{
- bool ret = false;
-
- if (new_state == NORMAL) {
- if (old_state == WARNING || old_state == LIMIT)
- ret = true;
- } else if (new_state == WARNING) {
- if (old_state == NORMAL)
- ret = true;
- } else if (new_state == LIMIT) {
- if (old_state == NORMAL || old_state == WARNING)
- ret = true;
- } else if (new_state == SHUTDOWN) {
- if (old_state != SHUTDOWN)
- ret = true;
+ default:
+ _E("Invalid state : %d", state);
}
- return ret;
-}
+ _D("Last old_state = %d, new_state = %d", old_state, state);
+ old_state = state;
-static int thermal_get_temp_enum(int temp)
-{
- int ret = -1;
-
- if (temp <= thermal_table.normal)
- ret = NORMAL;
- else if (temp >= thermal_table.shutdown)
- ret = SHUTDOWN;
- else if (temp >= thermal_table.limit)
- ret = LIMIT;
- else if (temp >= thermal_table.warning)
- ret = WARNING;
-
- return ret;
+ return 0;
}
-static int thermal_get_average(int temp)
+static int check_sender_process(GDBusConnection *conn, const char *sender)
{
- static int buf[SAMPLE_CNT] = {25, 25, 25, 25};
- static int index = 0;
- int i, avg_temp = 0;
-
- buf[index++] = temp;
- index %= SAMPLE_CNT;
-
- for (i = 0; i < SAMPLE_CNT; i++)
- avg_temp += buf[i];
+ pid_t pid;
- avg_temp /= SAMPLE_CNT;
- return avg_temp;
-}
-
-static void thermal_handler(struct thermal_info *info, void *data)
-{
- static int old_state = NORMAL;
- int avg_temp, new_state;
- bool action_needed = false;
-
- avg_temp = thermal_get_average(info->temp);
- new_state = thermal_get_temp_enum(avg_temp);
- if (new_state == -1) {
- _I("Keep current state: %d", old_state);
- return;
+ if (sender == NULL || g_dbus_is_name(sender) == FALSE) {
+ _E("Invalid sender.");
+ return -EINVAL;
}
- action_needed = is_action_needed(old_state, new_state);
- _I("Action=%d old_state=%d new_state=%d", action_needed, old_state, new_state);
- if (action_needed)
- thermal_action(new_state);
-
- old_state = new_state;
-}
-
-static int thermal_service_start(void)
-{
- int ret;
-
- if (!thermal_dev) {
- _E("Thermal service is not supported.");
- return -ENOTSUP;
+ pid = dbus_connection_get_sender_pid(conn, sender);
+ if (kill(pid, 0) == -1) {
+ _E("Process(%d) does not exist, dbus ignored.", pid);
+ return -ESRCH;
}
- ret = thermal_dev->register_changed_event(thermal_handler, NULL);
- if (ret < 0)
- _E("Failed to register thermal event: %d", ret);
-
- return ret;
+ return pid;
}
-static int thermal_service_stop(void)
+static GVariant *dbus_cooldown_handler(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
{
- int ret;
-
- if (!thermal_dev) {
- _E("Thermal service is not supported.");
- return -ENOTSUP;
- }
+ int ret = 0;
+ int val;
+ char *string;
- ret = thermal_dev->unregister_changed_event(thermal_handler);
+ g_variant_get(param, "(s)", &string);
+ _D("Cooldown string : %s", string);
+ ret = check_sender_process(conn, sender);
if (ret < 0)
- _E("Failed to unregister thermal event: %d", ret);
+ goto out;
+
+ val = get_action_id(string);
+ if (val < 0) {
+ _E("Invalid value : %d", val);
+ ret = val;
+ goto out;
+ } else
+ ret = cool_down_execute(val);
- return ret;
+out:
+ free(string);
+ return g_variant_new("(i)", ret);
}
static GVariant *dbus_get_temperature(GDBusConnection *conn,
static const dbus_method_s dbus_methods[] = {
{ "GetTemperature", "i", "i", dbus_get_temperature},
+ { "ChangedCooldownMode", "s", "i", dbus_cooldown_handler},
/* Add methods here */
};
.nr_methods = ARRAY_SIZE(dbus_methods),
};
-static int booting_done(void *data)
-{
- static int done;
-
- if (data == NULL)
- return done;
- done = *(int *)data;
- if (done == 0)
- return done;
-
- _I("Booting done.");
- thermal_service_start();
-
- return done;
-}
-
-static int load_config(struct parse_result *result, void *user_data)
-{
- struct thermal_config_info *info = user_data;
- char *name;
- char *value;
-
- _D("Load config. section=%s name=%s value=%s", result->section, result->name, result->value);
-
- if (!info)
- return -EINVAL;
-
- if (!MATCH(result->section, "THERMAL"))
- return -EINVAL;
-
- name = result->name;
- value = result->value;
- if (MATCH(name, "Normal"))
- info->normal = atoi(value);
- else if (MATCH(name, "Warning"))
- info->warning = atoi(value);
- else if (MATCH(name, "Limit"))
- info->limit = atoi(value);
- else if (MATCH(name, "Shutdown"))
- info->shutdown = atoi(value);
-
- return 0;
-}
-
static void thermal_init(void *data)
{
int ret;
- /* load thermal configuration file */
- ret = config_parse(THERMAL_CONF_FILE, load_config, &thermal_table);
- if (ret < 0)
- _E("Failed to load power off config: %d", ret);
-
- _I("Temperature conf normal=%d warning=%d limit=%d shutdown=%d", thermal_table.normal, thermal_table.warning,
- thermal_table.limit, thermal_table.shutdown);
-
ret = register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
if (ret < 0)
_E("Failed to register booting done notifier.");
ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_TEMPERATURE, &dbus_interface);
if (ret < 0)
_E("Failed to init dbus method: %d", ret);
+
+ if (vconf_set_int(VCONFKEY_SYSMAN_COOL_DOWN_MODE, COOL_DOWN_NONE_INIT) != 0)
+ _E("Failed to set VCONFKEY_SYSMAN_COOL_DOWN_MODE : %d", COOL_DOWN_NONE_INIT);
}
static void thermal_exit(void *data)
ret = unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
if (ret < 0)
_E("Failed to unregister booting done notifier.");
-
- thermal_service_stop();
}
static int thermal_probe(void *data)