2 // Copyright (c) 2015 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
22 #include <sys/types.h>
23 #include <sys/socket.h>
26 #include <hardware/activity_recognition.h>
27 #include <hardware/sensors.h>
28 #include <utils/Log.h>
30 #include "activity_event_utils.h"
32 /* Return error codes */
34 #define HAL_ACCESS_ERR 1
35 #define HAL_OPEN_ERR 2
36 #define HAL_SYMBOL_ERR 3
38 #define START_CMD "start"
39 #define STOP_CMD "stop"
40 #define REGISTER_CMD "register_callback"
41 #define ENABLE_CMD "enable"
42 #define DISABLE_CMD "disable"
43 #define LIST_CMD "list"
44 #define FLUSH_CMD "flush"
45 #define MONITOR_START_CMD "monitor_start"
46 #define MONITOR_STOP_CMD "monitor_stop"
48 #define MAX_CMD_SIZE 512
51 #define CMD_SEPARATOR " "
54 #define MONITOR_START_FLAG 2
55 #define MONITOR_STOP_FLAG 3
57 /* We define a default latency since current HAL does not use this latency */
58 #define DEFAULT_LATENCY 0
60 static struct activity_recognition_module *hmi;
61 static struct hw_device_t *device;
63 static FILE *client, *monitor_client;
64 static int monitor_connection = -1;
67 #define ACTIVITY_SERVER_NAME "/dev/socket/activity-server"
69 #define ACTIVITY_SERVER_NAME "/tmp/activity-server"
72 #define CLIENT_ERR(f, fmt...) \
73 { if (f) { fprintf(f, fmt); fprintf(f, "\n"); } ALOGE(fmt); }
75 struct sockaddr_un server_addr = {
76 .sun_family = AF_UNIX,
77 .sun_path = ACTIVITY_SERVER_NAME,
80 /* Event types are indexed so that a type is positioned at an index represented
81 * by its value in the ACTIVITY_TYPE_* enum in activity_recognition.h .
83 static const char* event_types[] = {
89 static void dummy_activity_callback(const activity_recognition_callback_procs_t *procs __attribute((unused)),
90 const activity_event_t *events, int count)
94 /* Exit if nobody is monitoring */
95 if (monitor_client == NULL)
98 fprintf(monitor_client, "No. of activity events: %d\n", count);
100 for (i = 0; i < count; i++)
101 fprintf(monitor_client, "\t<activity [%d], event %s> occurred at %lld (ns)\n",
103 event_types[events[i].event_type],
104 events[i].timestamp);
107 static activity_recognition_callback_procs_t dummy_callback_procs = {
108 .activity_callback = dummy_activity_callback
111 /* We register a dummy callback that just prints the events reported from HAL. */
112 static void register_activity_callback(void)
114 struct activity_recognition_device *activity_dev =
115 (struct activity_recognition_device *) device;
117 activity_dev->register_activity_callback(activity_dev, &dummy_callback_procs);
120 static int enable_activity_event(uint32_t handle, uint32_t event_type)
122 struct activity_recognition_device *activity_dev =
123 (struct activity_recognition_device *) device;
125 return activity_dev->enable_activity_event(activity_dev, handle,
126 event_type, DEFAULT_LATENCY);
129 static int disable_activity_event(uint32_t handle, uint32_t event_type)
131 struct activity_recognition_device *activity_dev =
132 (struct activity_recognition_device*) device;
134 return activity_dev->disable_activity_event(activity_dev, handle, event_type);
137 static int flush(void)
139 struct activity_recognition_device *activity_dev =
140 (struct activity_recognition_device *) device;
142 return activity_dev->flush(activity_dev);
145 static int print_usage(void)
147 fprintf(stderr, "Program usage:\n");
148 fprintf(stderr, "\tactivity %s\n", START_CMD);
149 fprintf(stderr, "\tactivity %s\n", STOP_CMD);
150 fprintf(stderr, "\tactivity %s\n", REGISTER_CMD);
151 fprintf(stderr, "\tactivity %s\n", LIST_CMD);
152 fprintf(stderr, "\tactivity %s <activity_id> <event_type>\n", ENABLE_CMD);
153 fprintf(stderr, "\tactivity %s <activity_id> <event_type>\n", DISABLE_CMD);
154 fprintf(stderr, "\tactivity %s\n", FLUSH_CMD);
155 fprintf(stderr, "\tactivity %s\n", MONITOR_START_CMD);
156 fprintf(stderr, "\tactivity %s\n", MONITOR_STOP_CMD);
157 fprintf(stderr, "\t* <activity_id> is the index of the activity as shown by running \"activity list\"\n");
158 fprintf(stderr, "\t* <event_type> is one of the following:\n");
159 fprintf(stderr, "\t\t%d => activity event ENTER\n", ACTIVITY_EVENT_ENTER);
160 fprintf(stderr, "\t\t%d => activity event EXIT\n", ACTIVITY_EVENT_EXIT);
161 fprintf(stderr, "\t\t%d => activity event FLUSH COMPLETE\n", ACTIVITY_EVENT_FLUSH_COMPLETE);
166 static int parse_cmd(char buffer[])
168 char *tmp, *args[MAX_ARGS];
171 tmp = strtok(buffer, CMD_SEPARATOR);
175 tmp = strtok(NULL, CMD_SEPARATOR);
179 CLIENT_ERR(client, "Invalid command %s", buffer);
183 if (strncmp(args[0], STOP_CMD, sizeof(STOP_CMD)) == 0) {
185 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
186 'activity %s'", STOP_CMD);
188 fprintf(client, "Stopping server\n");
192 unlink(ACTIVITY_SERVER_NAME);
197 if (strncmp(args[0], LIST_CMD, sizeof(LIST_CMD)) == 0) {
198 const char * const* activities;
202 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
203 'activity %s'", LIST_CMD);
204 size = hmi->get_supported_activities_list(hmi, &activities);
206 fprintf(client, "Activities list:\n");
207 for (i = 0; i < size; i++)
208 fprintf(client, "\t[%d] %s\n", i + 1, activities[i]);
214 if (strncmp(args[0], REGISTER_CMD, sizeof(REGISTER_CMD)) == 0) {
216 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
217 'activity %s'", REGISTER_CMD);
218 register_activity_callback();
223 if (strncmp(args[0], ENABLE_CMD, sizeof(ENABLE_CMD)) == 0) {
225 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
226 'activity %s %s %s'", ENABLE_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>'", ENABLE_CMD);
233 return enable_activity_event(atoi(args[1]), atoi(args[2]));
236 if (strncmp(args[0], DISABLE_CMD, sizeof(DISABLE_CMD)) == 0) {
238 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
239 'activity %s %s %s'", DISABLE_CMD, args[1], args[2])
240 else if (count != 3) {
241 CLIENT_ERR(client, "Insufficient arguments. Command should be \
242 'activity %s <activity_handle> <event_type>'", DISABLE_CMD);
246 return disable_activity_event(atoi(args[1]), atoi(args[2]));
249 if (strncmp(args[0], FLUSH_CMD, sizeof(FLUSH_CMD)) == 0) {
251 CLIENT_ERR(client, "Too many arguments. Trimming command down to \
252 'activity %s'", FLUSH_CMD);
257 if (strncmp(args[0], MONITOR_START_CMD, sizeof(MONITOR_START_CMD)) == 0) {
259 CLIENT_ERR(client, "Too many arguments. Trimming command \
260 down to 'activity %s'", MONITOR_START_CMD);
261 return MONITOR_START_FLAG;
264 if (strncmp(args[0], MONITOR_STOP_CMD, sizeof(MONITOR_STOP_CMD)) == 0) {
266 CLIENT_ERR(client, "Too many arguments. Trimming command \
267 down to 'activity %s'", MONITOR_STOP_CMD);
268 return MONITOR_STOP_FLAG;
271 CLIENT_ERR(client, "Invalid command %s", buffer);
276 static void stop_monitoring(int *flag)
278 int current_flag = ACK_FLAG;
280 /* Send ACK to client */
281 write(monitor_connection, ¤t_flag, sizeof(current_flag));
284 fclose(monitor_client);
285 close(monitor_connection);
286 monitor_client = NULL;
287 monitor_connection = -1;
292 static void start_monitoring(int conn, int *flag)
294 /* Stop other started monitor if that's the case */
295 if (monitor_client != NULL)
296 stop_monitoring(flag);
298 monitor_client = client;
299 monitor_connection = conn;
300 *flag = MONITOR_START_FLAG;
304 static void start_server(void)
309 /* Just to make sure we do not have more than one server instance */
310 unlink(ACTIVITY_SERVER_NAME);
312 sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
314 ALOGE("Error %s creating socket\n", strerror(errno));
318 ret = bind(sock, (struct sockaddr *) &server_addr, sizeof(server_addr));
320 ALOGE("Error %s binding socket\n", strerror(errno));
324 ret = listen(sock, 1);
326 ALOGW("Error %s setting socket to listening state\n", strerror(errno));
328 /* Accept commands and send them to HAL */
330 char buffer[526], cmsg_buffer[526];
331 struct sockaddr_un from;
332 struct iovec recv_buff = {
334 .iov_len = sizeof(buffer),
336 struct msghdr msg = {
338 .msg_namelen = sizeof(from),
339 .msg_iov = &recv_buff,
341 .msg_control = cmsg_buffer,
342 .msg_controllen = sizeof(cmsg_buffer),
344 struct cmsghdr *cmsg;
345 bool close_now = true;
347 conn = accept(sock, NULL, NULL);
349 ALOGE("Error %s accepting connection\n", strerror(errno));
353 ret = recvmsg(conn, &msg, 0);
355 ALOGE("Error %s in receiving message, conn = %d\n", strerror(errno), conn);
364 /* Check for shutdown from the peer */
368 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
369 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
370 int *received_fd = (int *)CMSG_DATA(cmsg);
371 client = fdopen(*received_fd, "w");
376 ret = parse_cmd(buffer);
381 if (ret == MONITOR_START_FLAG) {
382 start_monitoring(conn, &flag);
384 } else if (ret == MONITOR_STOP_FLAG)
385 stop_monitoring(&flag);
389 /* Confirm succesfull dispatch */
390 write(conn, &flag, sizeof(flag));
399 static const char *hal_paths[] ={
400 "./activity.gmin.so",
401 "/lib/activity.gmin.so",
402 "/system/lib/hw/activity.gmin.so",
405 static int start_hal(void)
408 int i, ret, no_paths;
409 const char *path = NULL;
412 no_paths = sizeof(hal_paths)/sizeof(const char*);
413 for (i = 0; i < no_paths; i++) {
414 if (access(hal_paths[i], R_OK) == 0) {
421 fprintf(stderr, "Unable to find HAL\n");
425 hal = dlopen(path, RTLD_NOW);
427 fprintf(stderr, "Error \"%s\" opening activity HAL\n", dlerror());
431 hmi = dlsym(hal, HAL_MODULE_INFO_SYM_AS_STR);
433 fprintf(stderr, "Error \"%s\" finding entry symbol\n", dlerror());
434 return HAL_SYMBOL_ERR;
437 printf("Activity HAL loaded: name %s vendor %s version %d.%d id %s\n",
438 hmi->common.name, hmi->common.author,
439 hmi->common.version_major, hmi->common.version_minor,
449 if (setsid() == (pid_t)-1) {
450 fprintf(stderr, "failed to send process to background\n");
455 close(0); close(1); close(2);
457 ALOGI("Proceeding to HAL initialization\n");
459 ret = hmi->common.methods->open((struct hw_module_t *) hmi,
460 ACTIVITY_RECOGNITION_HARDWARE_INTERFACE,
463 ALOGE("Error %d occurred at HAL module opening\n", ret);
472 static int send_cmd(int argc, char **argv)
474 char cmd[MAX_CMD_SIZE];
475 int i, sock, ret, flag;
476 struct iovec rcv_buffer = {
478 .iov_len = sizeof(cmd) + 1,
485 .cmsg_level = SOL_SOCKET,
486 .cmsg_type = SCM_RIGHTS,
487 .cmsg_len = CMSG_LEN(sizeof(int)),
491 struct msghdr msg = {
494 .msg_iov = &rcv_buffer,
496 .msg_control = &cmsg_buff,
497 .msg_controllen = sizeof(cmsg_buff),
500 strcpy(cmd, argv[1]);
501 for (i = 2; i < argc; i++) {
502 strncat(cmd, CMD_SEPARATOR, sizeof(CMD_SEPARATOR));
503 strcat(cmd, argv[i]);
506 sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
508 fprintf(stderr, "Error \"%s\" creating socket\n", strerror(errno));
512 ret = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
514 fprintf(stderr, "Error \"%s\" connecting to server\n", strerror(errno));
518 ret = sendmsg(sock, &msg, 0);
520 fprintf(stderr, "Error \"%s\" sending message to server\n", strerror(errno));
524 ret = read(sock, &flag, sizeof(flag));
526 fprintf(stderr, "Error \"%s\" getting answer from server\n", strerror(errno));
530 /* Check for ACK or monitoring */
531 if (flag == MONITOR_START_FLAG) {
533 ret = read(sock, &flag, sizeof(flag));
534 } while (ret > 0 && flag != ACK_FLAG);
535 } else if (flag != ACK_FLAG)
536 fprintf(stderr, "Error answer from HAL server: %d. Check logs for more details\n", flag);
543 static int run_cmd(int argc, char **argv)
545 if (strncmp(argv[1], START_CMD, sizeof(START_CMD)) == 0) {
548 return print_usage();
551 /* Send user command to HAL server socket */
552 return send_cmd(argc, argv);
555 int main(int argc, char **argv)
558 return print_usage();
560 return run_cmd(argc, argv);