Thermal SW Architectures on HAL
Peter xu, 2012.08
*************************************************************************************************************
Agenda
SW Architecture
HAL part (System_monitor service)
How to start
System_monitor workflow
Parse startup options
Load plugin
Parse configure file
Open server socket
Enable all sensors
How to create plugin(type=SENSOR)
How to create plugin(type=MITIGATION)
*************************************************************************************************************
Architecture
*************************************************************************************************************
HAL PART: System_monitor service
How to start
System_monitor workflow
Parse startup options
Load plugin
Parse configure file
Open server socket
Enable all sensors
How to create plugin(type=SENSOR)
How to create plugin(type=MITIGATION)
*************************************************************************************************************
How to start
@ device/semc/viscan/files/init.viskan.rc
# use system_monitor
service system_monitor /system/bin/system_monitor
class core
user root
System_monitor run as service, that is the process cannot be killed and run always.
No startup options
Check the process
$adb shell ps | grep system_monitor
*************************************************************************************************************
System_monitor workflow
*************************************************************************************************************
Parse startup options (parse_options)
$adb shell
#system/bin/system_monitor –h
-h Print this help text
-c Complete path and name of config file
-n Number of clients this server can support
-p Path to the plugins
-s Complete path and name where the communication socket will be created
-l List all available sensors
-a List all available actions
For example:
#system/bin/system_monitor –c /system/etc/sysmon.cfg
#system/bin/system_monitor –n 5
#system/bin/system_monitor –p /system/lib/sysmon/
#system/bin/system_monitor –s /tmp/sysmon.skt
#system/bin/system_monitor –l //register plug in type=SENSOR
#system/bin/system_monitor –a //register plug in type=MITIGATION
*************************************************************************************************************
Load plugin (load_plugins)
The path of share library
/system/lib/sysmon/*.so
Each plugin share library must include the function, as following
struct sysmon_plugin *tp_init(void)
struct sysmon_plugin {
const char *name; /* Name of sensor or mitigation */
const enum plugin_type type; /* Type of plugin */
int (*start_plugin)(void); /* Start plugin. Always be called */
…
union {
struct sensor_if {…
void (*listen_for_event)(event_callback_t callback, void *data);
} sensor;
struct mitigation_if {
int (*execute_action)(void *data);
} mitigation;
/* Add new types below this line */
} interface;
Add plugin into plugin_list[2] according to the plugin type(SENSOR, MITIGATION)
Run initial function: start_plugin
*************************************************************************************************************
Load plugin workflow
*************************************************************************************************************
Parse configure file (parse_config_file)
The default path of configure file: /system/etc/sysmon.cfg
Configure Format:
<Sensor> <Level> <MinAlarm> <MaxAlarm> <poll freq> <Actions>:<Parameter> [...<Actions>:<Parameter>]
For example:
bat_ctrl 2 18 43 5 NOTIFY lcd_brightness_reset
batt_therm CRITICAL 1 NONE // critical level without min/max threshold
Sensor name: bat_ctrl batt_therm
Alarm level: 2 CRITICAL
Min alarm: 18
Max alarm: 43
Poll times: 5 1
Actions: NOTIFY, lcd_brightness_reset NONE
Important struct
struct sensor {
pthread_mutex_t lock;
struct sensor *next;
char *sensor_name; //one of plugin names
int last_level;
int current_level; //initial value is the lowest level
struct alarm_level *levels[NUM_LEVELS]; //NUM_LEVELS=33, the number of alarm level must be less than 33, ascending sort for alarm level from level=0 to level=32
};
struct alarm_level {
int level; //alarm level >= 0, CRITICAL=0, others +=1, for example: if Alarm Level=0 in configure file, the level will be 1.
int max_alarm; //the threshold of max alarm value
int min_alarm; //the threshold of min alarm value
int poll_time; //the poll delay time
int shutdown; //for the alarm, mobile phone should be shutdown if shutdown=1
int notify; // for the alarm, send notify message to application/framework if notify=1
struct action_entry *action_list; //for one alarm level, there could be more actions
};
struct action_entry {
char *action; //action name
int variable_param; //action parameter value
struct action_entry *next;
};
*************************************************************************************************************
Parse configure file workflow
*************************************************************************************************************
Create server socket (socket_open)
Main purpose:
Listen client connect from application and framework
Send notify message to client socket
Socket file default path: /tmp/sysmon.skt
Max number of unconnected client socket in the connection queue: 5
Create server socket thread
socket(AF_UNIX, SOCK_STREAM, 0) //socket type= SOCK_STREAM
bind(…) //set socket file path
listen(…) //start listen
accept(…) //wait for a new client to arrived & build our localstruct
Add client socket into socket_clients
Send notify message from server to client
Create client socket thread //manage communication with the client
Receive command from client
Send response from server to client
Main structs
struct socket_data {
pthread_t socket_server_pid; //socket server thread id
int socket_server_fd; //server socket id
socket_client_t *socket_clients; //save the all connected client socket
pthread_mutex_t socket_clients_lock;
char *unix_socket_path; //socket file path
int max_clients; //the max number of unconnected clients in the connection queue
};
typedef struct socket_client_s {
int fd; //client socket id
pthread_t pid; //socket client thread id
struct socket_client_s *next;
} socket_client_t;
*************************************************************************************************************
Create server socket workflow
*************************************************************************************************************
Enable all sensors (sensor_enable_all_sensors)
Only start listening on those sensors registered via the configure file.
That is the sensors must be in configured_sensors.
The sensor must have matched plugin
All plugins(type=SENSOR) should have the function interface.sensor.listen_for_event
All plugins(type=MITIGATION) should have the function interface.mitigation.execute_action
The function of [email protected] is the key callback function for all sensors.
Main functions
void sensor_enable_all_sensors(event_callback_t cb, void *data)
{…
p = find_plugin_by_name(s->sensor_name); //find the matchedplugin
…
if (p->interface.sensor.listen_for_event)
p->interface.sensor.listen_for_event(cb, data); //calllisten_for_event
…
}
*************************************************************************************************************
System_monitor process block (socket_wait)
Hold the process of system_monitor
The key function
pthread_join(data->socket_server_pid, NULL);
The main thread will wait for the socket server thread to terminate
Blocking call that waits for the server thread to shutdown
*************************************************************************************************************
How to create plugin(type=SENSOR)
For example: @device/semc/viskan/sysmon/pm8921_sensor.c
Create more plugins(type=SENSOR) with same one file of pm8921_sensor.c by different complier configure settings.
@device/semc/viskan/sysmon/Android.mk
# xo_therm
ifeq ($(SEMC_CFG_SYSMON_SENSOR_PM8921_XO_THERM),yes)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -DTZ_USE_HW_UNIT
LOCAL_CFLAGS += -DPM8921_SENSOR_NAME=\"xo_therm\"
LOCAL_SRC_FILES := pm8921_sensor.c
LOCAL_MODULE := sysmon_xo_therm
include $(LOCAL_PATH)/main.mk
endif
# batt_therm
ifeq ($(SEMC_CFG_SYSMON_SENSOR_PM8921_BATT_THERM),yes)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -DPM8921_SENSOR_NAME=\"batt_therm\"
LOCAL_SRC_FILES := pm8921_sensor.c
LOCAL_MODULE := sysmon_batt_therm
include $(LOCAL_PATH)/main.mk
endif
Only change macro of PM8921_SENSOR_NAME, the source file is same file of pm8921_sensor.c.
The module name is different too, so generate different share library *.so
How to create plugin(type=SENSOR) cont’
Main structs and functions
struct sysmon_plugin *tp_init(void)
{ return &plg;}
static struct sysmon_plugin plg = {
.name = SENSOR_NAME, // #define SENSOR_NAME PM8921_SENSOR_NAME
.type = SENSOR,
.start_plugin = start_plugin,
…
.interface.sensor = {…
.listen_for_event = listen_for_event,
},
};
struct plg_data {
char *sensor_name; /* sensor_name */
char *input_path; /*the matched driver file node*/
int poll_delay; /* polling delay time */
int temp_value; /* temperature_value */
int min_alarm; /* min alarm value */
int max_alarm; /* max alarm value */
pthread_t thread_id; /* sensor thread ID */
sem_t sem;
event_callback_t cb; /* callback function when to trigger alarm*/
void *call_data;
pthread_mutex_t lock;
};
How to create plugin(type=SENSOR) cont’
static int start_plugin(void)
{…
rc = find_pm8921_sensor_path(plg.name); //check whether there is the driver file node or not
if (rc < 0) {
LOGE("%s - Failed to find correct sysfs interface. Aborting\n",
__func__);
return -ENODEV;
} else {
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf) - 1, PM8921_SENSOR_PATH SENSOR_NAME_PARAM, plg.name);// for example: /sys/bus/platform/devices/pm8xxx-adc/batt_therm
}
data.sensor_name = strdup(plg.name);
data.input_path = strdup(buf); //set driver file path
…}
static void listen_for_event(event_callback_t callback, void *d)
{
if (callback && NULL == data.cb) {
if (pthread_create(&data.thread_id, PTHREAD_CREATE_JOINABLE, sensor_work, (void *)&data)) {
LOGE("%s - Failed to start worker thread\n“, __func__);
} else {
data.cb = callback; //[email protected]
data.call_data = d; //that is static structsysmon *td;@sysmons.c
sem_post(&data.sem);
}
} else {
pthread_create(&tid, NULL, stop_sensor_work, (void *)&data); // Since the thread can be sleeping, we need to start another thread that will kill it
}
}
How to create plugin(type=SENSOR) cont’
static void *sensor_work(void *data)
{…
fd = open(d->input_path, O_RDONLY); //open the driver file node, for example: /sys/bus/platform/devices/pm8xxx-adc/batt_therm
while (1) { //get the value of batt_therm, and check whether is more thanmax_alarm and less thanmin_alarm. If so, triggeralarm_callback
lseek(fd, 0, SEEK_SET);
memset(read_buf, 0, sizeof(read_buf));
/* get tsens temperature */
if (read(fd, read_buf, sizeof(read_buf)) != -1) { //get temperature value
/* read_buf: "Result:%lld Raw:%d\n" */
sscanf(read_buf, "Result:%d Raw:%*d\n", &val);
…
}
…
d->temp_value = val; //set current temperature value
min_val = d->min_alarm;
max_val = d->max_alarm;
if (val > max_val) {
d->cb(MAX_ALARM, d->sensor_name, d->call_data); //for example: alarm_callback(MAX_ALARM,batt_therm, td;@sysmons.c)
} else if (val < min_val) {
d->cb(MIN_ALARM, d->sensor_name, d->call_data);
}
wait:
/* Without locking, the worst that can happen is that we
* sleep an incorrect amount of time during one loop. Don't
* think this is something that should be avoided */
poll_sleep(d->poll_delay); //delay fixed time for next polling
}
….
}
*************************************************************************************************************
How to create plugin(type=SENSOR) workflow
*************************************************************************************************************
List all ready plugins (type=SENSOR) for viskan
*************************************************************************************************************
How to create plugin(type=MITIGATION)
For example: @vendor/semc/hardware/sysmon/plugins/brightness_level.c
@vendor/semc/hardware/sysmon/Android.mk
#sysmon_lcd_brightness_level module
ifeq ($(SEMC_CFG_SYSMON_MITIGATION_LCD_LEVEL),yes)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := brightness_level.c
LOCAL_MODULE := sysmon_lcd_brightness_level
include $(LOCAL_PATH)/main.mk
Endif
the source file is pm8921_sensor.c.
generate the share library /system/lib/sysmon/sysmon_lcd_brightness_level.so
*************************************************************************************************************
How to create plugin(type=MITIGATION) cont’
Main structs and functions
struct sysmon_plugin *tp_init(void)
{ return &plg;}
static struct sysmon_plugin plg = {
.name = MITIGATION_NAME, // #define MITIGATION_NAME "lcd_brightnesslevel"
.type = MITIGATION,
.start_plugin = start_plugin,
.deinit_plugin = deinit_plugin,
.enable_test_mode = enable_test_mode,
.interface.mitigation.execute_action = execute_action,
};
static int execute_action(void *data)
{
struct sensor *s = (struct sensor *)data;
…
l = s->levels[s->current_level];
a = l->action_list;
while (a) {
if (!strncmp(a->action, MITIGATION_NAME, strlen(a->action)))
break;
else
a = a->next;
}
…
log_idd(s, a);
return set_soft_level(BR_TO_RGB((unsigned int)a->variable_param));
…
}
*************************************************************************************************************
How to create plugin(type=MITIGATION) cont’
void alarm_callback(enum event_type type, const char *name,void *data)
{ …
if (l->notify) {
pi = find_plugin_by_name(NOTIFY_STRING);
if (pi && pi->interface.mitigation.execute_action)
pi->interface.mitigation.execute_action(s); //only call the notifysysmon_plugin inbuiltin.c
}
/* Perform all supported actions registered on this level */
a = l->action_list;
while (a) {
pi = find_plugin_by_name(a->action); //find matchedplugin with the same action name
if (pi)
LOGV("%s - found plugin name: %s", __func__, pi->name);
if (pi && strcmp(pi->name, NOTIFY_STRING)) //plugin name must not NOTIFY_STRING ("NOTIFY“)
if (pi->interface.mitigation.execute_action)
pi->interface.mitigation.execute_action(s); //do special action
a = a->next;
}
…
}
*************************************************************************************************************
List all ready plugins (type=MITIGATION) for viskan
*************************************************************************************************************
Conclusion
Easily to add new sensor for monitoring temperature of special component in future because of loading dynamic plugin(type=SENSOR) share library(*.so)
Easily to add new mitigation(action if the temperature of special component is abnormal) in future because of loading dynamic plugin(type=MITIGATION) share library(*.so)
Easily notify the message to application or framework which need monitor temperatures when some special component temperatures become abnormal because of the server-client socket mode
Easily to manage how to respond when abnormal temperature happens because of setting different configure file by user, such as what is the reasonable threshold of battery high temperature, what kind of actions should be done for mitigating the rising temperature.