/**************************************************************************** * apps/system/adb/logcat_service.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "adb.h" #include "logcat_service.h" #include "hal/hal_uv_priv.h" /**************************************************************************** * Private types ****************************************************************************/ typedef struct alog_service_s { adb_service_t service; uv_poll_t poll; int wait_ack; } alog_service_t; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void logcat_on_data_available(uv_poll_t * handle, int status, int events); /**************************************************************************** * Private Functions ****************************************************************************/ static int alog_on_write(adb_service_t *service, apacket *p) { UNUSED(p); UNUSED(service); return -1; } static void alog_on_kick(struct adb_service_s *service) { alog_service_t *svc = container_of(service, alog_service_t, service); if (!svc->wait_ack) { int ret; ret = uv_poll_start(&svc->poll, UV_READABLE, logcat_on_data_available); assert(ret == 0); } } static int alog_on_ack(adb_service_t *service, apacket *p) { UNUSED(p); alog_service_t *svc = container_of(service, alog_service_t, service); svc->wait_ack = 0; alog_on_kick(service); return 0; } static void close_cb(uv_handle_t *handle) { alog_service_t *service = container_of(handle, alog_service_t, poll); free(service); } static void alog_close(struct adb_service_s *service) { int fd; int ret; alog_service_t *svc = container_of(service, alog_service_t, service); ret = uv_fileno((uv_handle_t *)&svc->poll, &fd); assert(ret == 0); close(fd); uv_close((uv_handle_t *)&svc->poll, close_cb); } static const adb_service_ops_t logcat_ops = { .on_write_frame = alog_on_write, .on_ack_frame = alog_on_ack, .on_kick = alog_on_kick, .on_close = alog_close }; static void logcat_on_data_available(uv_poll_t * handle, int status, int events) { int ret; int fd; apacket_uv_t *ap; alog_service_t *service = container_of(handle, alog_service_t, poll); adb_client_uv_t *client = (adb_client_uv_t *)handle->data; ap = adb_uv_packet_allocate(client, 0); if (ap == NULL) { uv_poll_stop(handle); return; } if (status) { adb_log("status error %d\n", status); /* Fatal error, stop service */ goto exit_stop_service; } ret = uv_fileno((uv_handle_t *)handle, &fd); assert(ret == 0); ret = read(fd, ap->p.data, CONFIG_ADBD_PAYLOAD_SIZE); if (ret < 0) { adb_log("frame read failed %d %d\n", ret, errno); if (errno == EAGAIN) { /* TODO this should never happen */ goto exit_release_packet; } /* Fatal error, stop service */ goto exit_stop_service; } if (ret == 0) { goto exit_release_packet; } service->wait_ack = 1; uv_poll_stop(handle); ap->p.write_len = ret; ap->p.msg.arg0 = service->service.id; ap->p.msg.arg1 = service->service.peer_id; adb_send_data_frame(&client->client, &ap->p); return; exit_release_packet: adb_hal_apacket_release(&client->client, &ap->p); return; exit_stop_service: adb_service_close(&client->client, &service->service, &ap->p); } /**************************************************************************** * Public Functions ****************************************************************************/ adb_service_t * logcat_service(adb_client_t *client, const char *params) { int ret; alog_service_t *service = (alog_service_t *)malloc(sizeof(alog_service_t)); if (service == NULL) { return NULL; } service->service.ops = &logcat_ops; service->wait_ack = 0; /* TODO parse params string to extract logcat parameters */ ret = open(CONFIG_SYSLOG_DEVPATH, O_RDONLY | O_CLOEXEC); if (ret < 0) { adb_log("failed to open %s (%d)\n", CONFIG_SYSLOG_DEVPATH, errno); free(service); return NULL; } uv_handle_t *handle = adb_uv_get_client_handle(client); ret = uv_poll_init(handle->loop, &service->poll, ret); assert(ret == 0); service->poll.data = client; alog_on_kick(&service->service); return &service->service; }