2 * Copyright (C) 2015 Intel Corporation.
10 #include <sys/socket.h>
13 #include <hardware/activity_recognition.h>
14 #include <hardware/sensors.h>
15 #include <utils/Log.h>
17 #include "activity_event_utils.h"
19 /* Return error codes */
21 #define HAL_ACCESS_ERR 1
22 #define HAL_OPEN_ERR 2
23 #define HAL_SYMBOL_ERR 3
25 #define START_CMD "start"
26 #define STOP_CMD "stop"
27 #define REGISTER_CMD "register_callback"
28 #define ENABLE_CMD "enable"
29 #define DISABLE_CMD "disable"
30 #define LIST_CMD "list"
31 #define FLUSH_CMD "flush"
32 #define MONITOR_START_CMD "monitor_start"
33 #define MONITOR_STOP_CMD "monitor_stop"
35 #define MAX_CMD_SIZE 512
38 #define CMD_SEPARATOR " "
41 #define MONITOR_START_FLAG 2
42 #define MONITOR_STOP_FLAG 3
44 /* We define a default latency since current HAL does not use this latency */
45 #define DEFAULT_LATENCY 0
47 static struct activity_recognition_module *hmi;
48 static struct hw_device_t *device;
50 static FILE *client, *monitor_client;
51 static int monitor_connection = -1;
54 #define ACTIVITY_SERVER_NAME "/dev/socket/activity-server"
56 #define ACTIVITY_SERVER_NAME "/tmp/activity-server"
59 #define CLIENT_ERR(f, fmt...) \
60 { if (f) { fprintf(f, fmt); fprintf(f, "\n"); } ALOGE(fmt); }
62 struct sockaddr_un server_addr = {
63 .sun_family = AF_UNIX,
64 .sun_path = ACTIVITY_SERVER_NAME,
67 /* Event types are indexed so that a type is positioned at an index represented
68 * by its value in the ACTIVITY_TYPE_* enum in activity_recognition.h .
70 static const char* event_types[] = {
76 static void dummy_activity_callback(const activity_recognition_callback_procs_t *procs __attribute((unused)),
77 const activity_event_t *events, int count)
81 /* Exit if nobody is monitoring */
82 if (monitor_client == NULL)
85 fprintf(monitor_client, "No. of activity events: %d\n", count);
87 for (i = 0; i < count; i++)
88 fprintf(monitor_client, "\t<activity [%d], event %s> occurred at %lld (ns)\n",
90 event_types[events[i].event_type],
94 static activity_recognition_callback_procs_t dummy_callback_procs = {
95 .activity_callback = dummy_activity_callback
98 /* We register a dummy callback that just prints the events reported from HAL. */
99 static void register_activity_callback(void)
101 struct activity_recognition_device *activity_dev =
102 (struct activity_recognition_device *) device;
104 activity_dev->register_activity_callback(activity_dev, &dummy_callback_procs);
107 static int enable_activity_event(uint32_t handle, uint32_t event_type)
109 struct activity_recognition_device *activity_dev =
110 (struct activity_recognition_device *) device;
112 return activity_dev->enable_activity_event(activity_dev, handle,
113 event_type, DEFAULT_LATENCY);
116 static int disable_activity_event(uint32_t handle, uint32_t event_type)
118 struct activity_recognition_device *activity_dev =
119 (struct activity_recognition_device*) device;
121 return activity_dev->disable_activity_event(activity_dev, handle, event_type);
124 static int flush(void)
126 struct activity_recognition_device *activity_dev =
127 (struct activity_recognition_device *) device;
129 return activity_dev->flush(activity_dev);
132 static int print_usage(void)
134 fprintf(stderr, "Program usage:\n");
135 fprintf(stderr, "\tactivity %s\n", START_CMD);
136 fprintf(stderr, "\tactivity %s\n", STOP_CMD);
137 fprintf(stderr, "\tactivity %s\n", REGISTER_CMD);
138 fprintf(stderr, "\tactivity %s\n", LIST_CMD);
139 fprintf(stderr, "\tactivity %s <activity_id> <event_type>\n", ENABLE_CMD);
140 fprintf(stderr, "\tactivity %s <activity_id> <event_type>\n", DISABLE_CMD);
141 fprintf(stderr, "\tactivity %s\n", FLUSH_CMD);
142 fprintf(stderr, "\tactivity %s\n", MONITOR_START_CMD);
143 fprintf(stderr, "\tactivity %s\n", MONITOR_STOP_CMD);
144 fprintf(stderr, "\t* <activity_id> is the index of the activity as shown by running \"activity list\"\n");
145 fprintf(stderr, "\t* <event_type> is one of the following:\n");
146 fprintf(stderr, "\t\t%d => activity event ENTER\n", ACTIVITY_EVENT_ENTER);
147 fprintf(stderr, "\t\t%d => activity event EXIT\n", ACTIVITY_EVENT_EXIT);
148 fprintf(stderr, "\t\t%d => activity event FLUSH COMPLETE\n", ACTIVITY_EVENT_FLUSH_COMPLETE);
153 static int parse_cmd(char buffer[])
155 char *tmp, *args[MAX_ARGS];
158 tmp = strtok(buffer, CMD_SEPARATOR);
162 tmp = strtok(NULL, CMD_SEPARATOR);
166 CLIENT_ERR(client, "Invalid command %s", buffer);
170 if (strncmp(args[0], STOP_CMD, sizeof(STOP_CMD)) == 0) {
172 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
173 'activity %s'", STOP_CMD);
175 fprintf(client, "Stopping server\n");
179 unlink(ACTIVITY_SERVER_NAME);
184 if (strncmp(args[0], LIST_CMD, sizeof(LIST_CMD)) == 0) {
185 const char * const* activities;
189 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
190 'activity %s'", LIST_CMD);
191 size = hmi->get_supported_activities_list(hmi, &activities);
193 fprintf(client, "Activities list:\n");
194 for (i = 0; i < size; i++)
195 fprintf(client, "\t[%d] %s\n", i + 1, activities[i]);
201 if (strncmp(args[0], REGISTER_CMD, sizeof(REGISTER_CMD)) == 0) {
203 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
204 'activity %s'", REGISTER_CMD);
205 register_activity_callback();
210 if (strncmp(args[0], ENABLE_CMD, sizeof(ENABLE_CMD)) == 0) {
212 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
213 'activity %s %s %s'", ENABLE_CMD, args[1], args[2])
214 else if (count != 3) {
215 CLIENT_ERR(client, "Insufficient arguments. Command should be \
216 'activity %s <activity_handle> <event_type>'", ENABLE_CMD);
220 return enable_activity_event(atoi(args[1]), atoi(args[2]));
223 if (strncmp(args[0], DISABLE_CMD, sizeof(DISABLE_CMD)) == 0) {
225 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
226 'activity %s %s %s'", DISABLE_CMD, args[1], args[2])
227 else if (count != 3) {
228 CLIENT_ERR(client, "Insufficient arguments. Command should be \
229 'activity %s <activity_handle> <event_type>'", DISABLE_CMD);
233 return disable_activity_event(atoi(args[1]), atoi(args[2]));
236 if (strncmp(args[0], FLUSH_CMD, sizeof(FLUSH_CMD)) == 0) {
238 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
239 'activity %s'", FLUSH_CMD);
244 if (strncmp(args[0], MONITOR_START_CMD, sizeof(MONITOR_START_CMD)) == 0) {
246 CLIENT_ERR(client, "Too many arguments. Trimming command \
247 down to 'activity %s'", MONITOR_START_CMD);
248 return MONITOR_START_FLAG;
251 if (strncmp(args[0], MONITOR_STOP_CMD, sizeof(MONITOR_STOP_CMD)) == 0) {
253 CLIENT_ERR(client, "Too many arguments. Trimming command \
254 down to 'activity %s'", MONITOR_STOP_CMD);
255 return MONITOR_STOP_FLAG;
258 CLIENT_ERR(client, "Invalid command %s", buffer);
263 static void stop_monitoring(int *flag)
265 int current_flag = ACK_FLAG;
267 /* Send ACK to client */
268 write(monitor_connection, ¤t_flag, sizeof(current_flag));
271 fclose(monitor_client);
272 close(monitor_connection);
273 monitor_client = NULL;
274 monitor_connection = -1;
279 static void start_monitoring(int conn, int *flag)
281 /* Stop other started monitor if that's the case */
282 if (monitor_client != NULL)
283 stop_monitoring(flag);
285 monitor_client = client;
286 monitor_connection = conn;
287 *flag = MONITOR_START_FLAG;
291 static void start_server(void)
296 /* Just to make sure we do not have more than one server instance */
297 unlink(ACTIVITY_SERVER_NAME);
299 sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
301 ALOGE("Error %s creating socket\n", strerror(errno));
305 ret = bind(sock, (struct sockaddr *) &server_addr, sizeof(server_addr));
307 ALOGE("Error %s binding socket\n", strerror(errno));
311 ret = listen(sock, 1);
313 ALOGW("Error %s setting socket to listening state\n", strerror(errno));
315 /* Accept commands and send them to HAL */
317 char buffer[526], cmsg_buffer[526];
318 struct sockaddr_un from;
319 struct iovec recv_buff = {
321 .iov_len = sizeof(buffer),
323 struct msghdr msg = {
325 .msg_namelen = sizeof(from),
326 .msg_iov = &recv_buff,
328 .msg_control = cmsg_buffer,
329 .msg_controllen = sizeof(cmsg_buffer),
331 struct cmsghdr *cmsg;
332 bool close_now = true;
334 conn = accept(sock, NULL, NULL);
336 ALOGE("Error %s accepting connection\n", strerror(errno));
340 ret = recvmsg(conn, &msg, 0);
342 ALOGE("Error %s in receiving message, conn = %d\n", strerror(errno), conn);
351 /* Check for shutdown from the peer */
355 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
356 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
357 int *received_fd = (int *)CMSG_DATA(cmsg);
358 client = fdopen(*received_fd, "w");
363 ret = parse_cmd(buffer);
368 if (ret == MONITOR_START_FLAG) {
369 start_monitoring(conn, &flag);
371 } else if (ret == MONITOR_STOP_FLAG)
372 stop_monitoring(&flag);
376 /* Confirm succesfull dispatch */
377 write(conn, &flag, sizeof(flag));
386 static const char *hal_paths[] ={
387 "./activity.gmin.so",
388 "/lib/activity.gmin.so",
389 "/system/lib/hw/activity.gmin.so",
392 static int start_hal(void)
395 int i, ret, no_paths;
396 const char *path = NULL;
399 no_paths = sizeof(hal_paths)/sizeof(const char*);
400 for (i = 0; i < no_paths; i++) {
401 if (access(hal_paths[i], R_OK) == 0) {
408 fprintf(stderr, "Unable to find HAL\n");
412 hal = dlopen(path, RTLD_NOW);
414 fprintf(stderr, "Error \"%s\" opening activity HAL\n", dlerror());
418 hmi = dlsym(hal, HAL_MODULE_INFO_SYM_AS_STR);
420 fprintf(stderr, "Error \"%s\" finding entry symbol\n", dlerror());
421 return HAL_SYMBOL_ERR;
424 printf("Activity HAL loaded: name %s vendor %s version %d.%d id %s\n",
425 hmi->common.name, hmi->common.author,
426 hmi->common.version_major, hmi->common.version_minor,
436 if (setsid() == (pid_t)-1) {
437 fprintf(stderr, "failed to send process to background\n");
442 close(0); close(1); close(2);
444 ALOGI("Proceeding to HAL initialization\n");
446 ret = hmi->common.methods->open((struct hw_module_t *) hmi,
447 ACTIVITY_RECOGNITION_HARDWARE_INTERFACE,
450 ALOGE("Error %d occurred at HAL module opening\n", ret);
459 static int send_cmd(int argc, char **argv)
461 char cmd[MAX_CMD_SIZE];
462 int i, sock, ret, flag;
463 struct iovec rcv_buffer = {
465 .iov_len = sizeof(cmd) + 1,
472 .cmsg_level = SOL_SOCKET,
473 .cmsg_type = SCM_RIGHTS,
474 .cmsg_len = CMSG_LEN(sizeof(int)),
478 struct msghdr msg = {
481 .msg_iov = &rcv_buffer,
483 .msg_control = &cmsg_buff,
484 .msg_controllen = sizeof(cmsg_buff),
487 strcpy(cmd, argv[1]);
488 for (i = 2; i < argc; i++) {
489 strncat(cmd, CMD_SEPARATOR, sizeof(CMD_SEPARATOR));
490 strcat(cmd, argv[i]);
493 sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
495 fprintf(stderr, "Error \"%s\" creating socket\n", strerror(errno));
499 ret = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
501 fprintf(stderr, "Error \"%s\" connecting to server\n", strerror(errno));
505 ret = sendmsg(sock, &msg, 0);
507 fprintf(stderr, "Error \"%s\" sending message to server\n", strerror(errno));
511 ret = read(sock, &flag, sizeof(flag));
513 fprintf(stderr, "Error \"%s\" getting answer from server\n", strerror(errno));
517 /* Check for ACK or monitoring */
518 if (flag == MONITOR_START_FLAG) {
520 ret = read(sock, &flag, sizeof(flag));
521 } while (ret > 0 && flag != ACK_FLAG);
522 } else if (flag != ACK_FLAG)
523 fprintf(stderr, "Error answer from HAL server: %d. Check logs for more details\n", flag);
530 static int run_cmd(int argc, char **argv)
532 if (strncmp(argv[1], START_CMD, sizeof(START_CMD)) == 0) {
535 return print_usage();
538 /* Send user command to HAL server socket */
539 return send_cmd(argc, argv);
542 int main(int argc, char **argv)
545 return print_usage();
547 return run_cmd(argc, argv);