2016-03-01 22:45:42 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007-2016 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <endian.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdatomic.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2017-03-09 17:09:43 +01:00
|
|
|
#include <sys/socket.h>
|
2016-03-01 22:45:42 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <cutils/sockets.h>
|
|
|
|
#include <private/android_filesystem_config.h>
|
|
|
|
#include <private/android_logger.h>
|
|
|
|
|
|
|
|
#include "config_read.h"
|
|
|
|
#include "log_portability.h"
|
liblog: add android_lookupEventTagNum
android_lookupEventTagNum added. Adds support for creating a new
log tag at runtime, registered to the logd service.
Tested on Hikey, all services stopped, shell only access, CPUs not
locked (there is enough repeatability on this platform).
$ /data/nativetest64/liblog-benchmarks/liblog-benchmarks BM_lookupEventTagNum
iterations ns/op
Precharge: start
Precharge: stop 231
NB: only Tag matching, linear lookup (as reference, before unordered_map)
BM_lookupEventTagNum 1000000 1017
NB: unordered_map with full Tag & Format lookup, but with Tag hashing
BM_lookupEventTagNum 2000000 683
NB: with full Tag & Format hash and lookup for matching
BM_lookupEventTagNum 2000000 814
NB: only Tag matching (Hail Mary path)
BM_lookupEventTagNum 5000000 471
Because the database can now be dynamic, we added reader/writer locks
which adds a 65ns (uncontended) premium on lookups, and switch to
check for an allocation adds 25ns (either open code, or using
string_view, no difference) which means our overall speed takes 90%
as long as the requests did before we switched to unordered_map.
Faster than before where we originally utilized binary lookup on
static content, but not by much. Dynamic updates that are not cached
locally take the following times to acquire long path to logd to
generate.
BM_lookupEventTag 20000000 139
BM_lookupEventTag_NOT 20000000 87
BM_lookupEventFormat 20000000 139
BM_lookupEventTagNum_logd_new 5000 335936
BM_lookupEventTagNum_logd_existing 10000 249226
The long path pickups are mitigated by the built-in caching, and
the public mapping in /dev/event-log-tags.
SideEffects: Event tags and signal handlers do not mix
Test: liblog benchmarks
Bug: 31456426
Change-Id: I69e6489d899cf35cdccffcee0d8d7cad469ada0a
2016-09-21 18:24:13 +02:00
|
|
|
#include "logd_reader.h"
|
2016-03-01 22:45:42 +01:00
|
|
|
#include "logger.h"
|
|
|
|
|
|
|
|
/* branchless on many architectures. */
|
2017-03-09 17:09:43 +01:00
|
|
|
#define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
static int logdAvailable(log_id_t LogId);
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdVersion(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp);
|
|
|
|
static int logdRead(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp,
|
|
|
|
struct log_msg* log_msg);
|
|
|
|
static int logdPoll(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp);
|
|
|
|
static void logdClose(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp);
|
|
|
|
static int logdClear(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp);
|
|
|
|
static ssize_t logdSetSize(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp,
|
2016-03-01 22:45:42 +01:00
|
|
|
size_t size);
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdGetSize(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp);
|
|
|
|
static ssize_t logdGetReadableSize(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp);
|
|
|
|
static ssize_t logdGetPrune(struct android_log_logger_list* logger,
|
|
|
|
struct android_log_transport_context* transp,
|
|
|
|
char* buf, size_t len);
|
|
|
|
static ssize_t logdSetPrune(struct android_log_logger_list* logger,
|
|
|
|
struct android_log_transport_context* transp,
|
|
|
|
char* buf, size_t len);
|
|
|
|
static ssize_t logdGetStats(struct android_log_logger_list* logger,
|
|
|
|
struct android_log_transport_context* transp,
|
|
|
|
char* buf, size_t len);
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
|
2017-03-09 17:09:43 +01:00
|
|
|
.node = { &logdLoggerRead.node, &logdLoggerRead.node },
|
|
|
|
.name = "logd",
|
|
|
|
.available = logdAvailable,
|
|
|
|
.version = logdVersion,
|
|
|
|
.read = logdRead,
|
|
|
|
.poll = logdPoll,
|
|
|
|
.close = logdClose,
|
|
|
|
.clear = logdClear,
|
|
|
|
.getSize = logdGetSize,
|
|
|
|
.setSize = logdSetSize,
|
|
|
|
.getReadableSize = logdGetReadableSize,
|
|
|
|
.getPrune = logdGetPrune,
|
|
|
|
.setPrune = logdSetPrune,
|
|
|
|
.getStats = logdGetStats,
|
2016-03-01 22:45:42 +01:00
|
|
|
};
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdAvailable(log_id_t logId) {
|
|
|
|
if (logId >= LOG_ID_MAX) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (logId == LOG_ID_SECURITY) {
|
|
|
|
uid_t uid = __android_log_uid();
|
|
|
|
if (uid != AID_SYSTEM) {
|
|
|
|
return -EPERM;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
2017-03-09 17:09:43 +01:00
|
|
|
}
|
|
|
|
if (access("/dev/socket/logdw", W_OK) == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -EBADF;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
LIBLOG_WEAK int socket_local_client(const char* name, int namespaceId,
|
|
|
|
int type) {
|
|
|
|
errno = ENOSYS;
|
|
|
|
return -ENOSYS;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !_WIN32 */
|
|
|
|
|
|
|
|
#include <sys/select.h>
|
2017-03-09 17:09:43 +01:00
|
|
|
#include <sys/socket.h>
|
2016-03-01 22:45:42 +01:00
|
|
|
#include <sys/types.h>
|
2017-03-09 17:09:43 +01:00
|
|
|
#include <sys/un.h>
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
/* Private copy of ../libcutils/socket_local.h prevent library loops */
|
|
|
|
#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
|
|
|
|
#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
|
|
|
|
/* End of ../libcutils/socket_local.h */
|
|
|
|
|
|
|
|
#define LISTEN_BACKLOG 4
|
|
|
|
|
|
|
|
/* Documented in header file. */
|
2017-03-09 17:09:43 +01:00
|
|
|
LIBLOG_WEAK int socket_make_sockaddr_un(const char* name, int namespaceId,
|
|
|
|
struct sockaddr_un* p_addr,
|
|
|
|
socklen_t* alen) {
|
|
|
|
memset(p_addr, 0, sizeof(*p_addr));
|
|
|
|
size_t namelen;
|
|
|
|
|
|
|
|
switch (namespaceId) {
|
2016-03-01 22:45:42 +01:00
|
|
|
case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
|
|
|
|
#if defined(__linux__)
|
2017-03-09 17:09:43 +01:00
|
|
|
namelen = strlen(name);
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
/* Test with length +1 for the *initial* '\0'. */
|
|
|
|
if ((namelen + 1) > sizeof(p_addr->sun_path)) {
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
/*
|
|
|
|
* Note: The path in this case is *not* supposed to be
|
|
|
|
* '\0'-terminated. ("man 7 unix" for the gory details.)
|
|
|
|
*/
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
p_addr->sun_path[0] = 0;
|
|
|
|
memcpy(p_addr->sun_path + 1, name, namelen);
|
2016-03-01 22:45:42 +01:00
|
|
|
#else
|
2017-03-09 17:09:43 +01:00
|
|
|
/* this OS doesn't have the Linux abstract namespace */
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
|
|
|
|
/* unix_path_max appears to be missing on linux */
|
|
|
|
if (namelen >
|
|
|
|
sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
|
|
|
|
strcat(p_addr->sun_path, name);
|
2016-03-01 22:45:42 +01:00
|
|
|
#endif
|
2017-03-09 17:09:43 +01:00
|
|
|
break;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
case ANDROID_SOCKET_NAMESPACE_RESERVED:
|
2017-03-09 17:09:43 +01:00
|
|
|
namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
|
|
|
|
/* unix_path_max appears to be missing on linux */
|
|
|
|
if (namelen >
|
|
|
|
sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
|
|
|
|
strcat(p_addr->sun_path, name);
|
|
|
|
break;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
|
2017-03-09 17:09:43 +01:00
|
|
|
namelen = strlen(name);
|
|
|
|
/* unix_path_max appears to be missing on linux */
|
|
|
|
if (namelen >
|
|
|
|
sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
strcpy(p_addr->sun_path, name);
|
|
|
|
break;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
default:
|
2017-03-09 17:09:43 +01:00
|
|
|
/* invalid namespace id */
|
|
|
|
return -1;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
p_addr->sun_family = AF_LOCAL;
|
|
|
|
*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
|
|
|
|
return 0;
|
2016-03-01 22:45:42 +01:00
|
|
|
error:
|
2017-03-09 17:09:43 +01:00
|
|
|
return -1;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* connect to peer named "name" on fd
|
|
|
|
* returns same fd or -1 on error.
|
|
|
|
* fd is not closed on error. that's your job.
|
|
|
|
*
|
|
|
|
* Used by AndroidSocketImpl
|
|
|
|
*/
|
2017-03-09 17:09:43 +01:00
|
|
|
LIBLOG_WEAK int socket_local_client_connect(int fd, const char* name,
|
|
|
|
int namespaceId, int type __unused) {
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t alen;
|
|
|
|
int err;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (err < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (connect(fd, (struct sockaddr*)&addr, alen) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return fd;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
error:
|
2017-03-09 17:09:43 +01:00
|
|
|
return -1;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* connect to peer named "name"
|
|
|
|
* returns fd or -1 on error
|
|
|
|
*/
|
2017-03-09 17:09:43 +01:00
|
|
|
LIBLOG_WEAK int socket_local_client(const char* name, int namespaceId,
|
|
|
|
int type) {
|
|
|
|
int s;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
s = socket(AF_LOCAL, type, 0);
|
|
|
|
if (s < 0) return -1;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (0 > socket_local_client_connect(s, name, namespaceId, type)) {
|
|
|
|
close(s);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return s;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !_WIN32 */
|
|
|
|
/* End of ../libcutils/socket_local_client.c */
|
|
|
|
|
|
|
|
/* worker for sending the command to the logger */
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t send_log_msg(struct android_log_logger* logger, const char* msg,
|
|
|
|
char* buf, size_t buf_size) {
|
|
|
|
ssize_t ret;
|
|
|
|
size_t len;
|
|
|
|
char* cp;
|
|
|
|
int errno_save = 0;
|
|
|
|
int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_STREAM);
|
|
|
|
if (sock < 0) {
|
|
|
|
return sock;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (msg) {
|
|
|
|
snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned)-1);
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
len = strlen(buf) + 1;
|
|
|
|
ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
|
|
|
|
if (ret <= 0) {
|
|
|
|
goto done;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
len = buf_size;
|
|
|
|
cp = buf;
|
|
|
|
while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
|
|
|
|
struct pollfd p;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
|
|
|
|
break;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
len -= ret;
|
|
|
|
cp += ret;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
p.fd = sock;
|
|
|
|
p.events = POLLIN;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
/* Give other side 20ms to refill pipe */
|
|
|
|
ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (ret <= 0) {
|
|
|
|
break;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (!(p.revents & POLLIN)) {
|
|
|
|
ret = 0;
|
|
|
|
break;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
2017-03-09 17:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret >= 0) {
|
|
|
|
ret += buf_size - len;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
|
|
|
done:
|
2017-03-09 17:09:43 +01:00
|
|
|
if ((ret == -1) && errno) {
|
|
|
|
errno_save = errno;
|
|
|
|
}
|
|
|
|
close(sock);
|
|
|
|
if (errno_save) {
|
|
|
|
errno = errno_save;
|
|
|
|
}
|
|
|
|
return ret;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf, size_t buf_size) {
|
|
|
|
return send_log_msg(NULL, NULL, buf, buf_size);
|
liblog: add android_lookupEventTagNum
android_lookupEventTagNum added. Adds support for creating a new
log tag at runtime, registered to the logd service.
Tested on Hikey, all services stopped, shell only access, CPUs not
locked (there is enough repeatability on this platform).
$ /data/nativetest64/liblog-benchmarks/liblog-benchmarks BM_lookupEventTagNum
iterations ns/op
Precharge: start
Precharge: stop 231
NB: only Tag matching, linear lookup (as reference, before unordered_map)
BM_lookupEventTagNum 1000000 1017
NB: unordered_map with full Tag & Format lookup, but with Tag hashing
BM_lookupEventTagNum 2000000 683
NB: with full Tag & Format hash and lookup for matching
BM_lookupEventTagNum 2000000 814
NB: only Tag matching (Hail Mary path)
BM_lookupEventTagNum 5000000 471
Because the database can now be dynamic, we added reader/writer locks
which adds a 65ns (uncontended) premium on lookups, and switch to
check for an allocation adds 25ns (either open code, or using
string_view, no difference) which means our overall speed takes 90%
as long as the requests did before we switched to unordered_map.
Faster than before where we originally utilized binary lookup on
static content, but not by much. Dynamic updates that are not cached
locally take the following times to acquire long path to logd to
generate.
BM_lookupEventTag 20000000 139
BM_lookupEventTag_NOT 20000000 87
BM_lookupEventFormat 20000000 139
BM_lookupEventTagNum_logd_new 5000 335936
BM_lookupEventTagNum_logd_existing 10000 249226
The long path pickups are mitigated by the built-in caching, and
the public mapping in /dev/event-log-tags.
SideEffects: Event tags and signal handlers do not mix
Test: liblog benchmarks
Bug: 31456426
Change-Id: I69e6489d899cf35cdccffcee0d8d7cad469ada0a
2016-09-21 18:24:13 +02:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static int check_log_success(char* buf, ssize_t ret) {
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (strncmp(buf, "success", 7)) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return 0;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdClear(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp __unused) {
|
|
|
|
char buf[512];
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return check_log_success(buf,
|
|
|
|
send_log_msg(logger, "clear %d", buf, sizeof(buf)));
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the total size of the log's ring buffer */
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdGetSize(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp __unused) {
|
|
|
|
char buf[512];
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((buf[0] < '0') || ('9' < buf[0])) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return atol(buf);
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdSetSize(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp __unused,
|
|
|
|
size_t size) {
|
|
|
|
char buf[512];
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns the readable size of the log's ring buffer (that is, amount of the
|
|
|
|
* log consumed)
|
|
|
|
*/
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdGetReadableSize(struct android_log_logger* logger,
|
|
|
|
struct android_log_transport_context* transp
|
|
|
|
__unused) {
|
|
|
|
char buf[512];
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((buf[0] < '0') || ('9' < buf[0])) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return atol(buf);
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns the logger version
|
|
|
|
*/
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdVersion(struct android_log_logger* logger __unused,
|
|
|
|
struct android_log_transport_context* transp __unused) {
|
|
|
|
uid_t uid = __android_log_uid();
|
|
|
|
return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns statistics
|
|
|
|
*/
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdGetStats(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp __unused,
|
|
|
|
char* buf, size_t len) {
|
|
|
|
struct android_log_logger* logger;
|
|
|
|
char* cp = buf;
|
|
|
|
size_t remaining = len;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
n = snprintf(cp, remaining, "getStatistics");
|
|
|
|
n = min(n, remaining);
|
|
|
|
remaining -= n;
|
|
|
|
cp += n;
|
|
|
|
|
|
|
|
logger_for_each(logger, logger_list) {
|
|
|
|
n = snprintf(cp, remaining, " %d", logger->logId);
|
2016-03-01 22:45:42 +01:00
|
|
|
n = min(n, remaining);
|
|
|
|
remaining -= n;
|
|
|
|
cp += n;
|
2017-03-09 17:09:43 +01:00
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (logger_list->pid) {
|
|
|
|
snprintf(cp, remaining, " pid=%u", logger_list->pid);
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return send_log_msg(NULL, NULL, buf, len);
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdGetPrune(struct android_log_logger_list* logger_list __unused,
|
|
|
|
struct android_log_transport_context* transp __unused,
|
|
|
|
char* buf, size_t len) {
|
|
|
|
return send_log_msg(NULL, "getPruneList", buf, len);
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static ssize_t logdSetPrune(struct android_log_logger_list* logger_list __unused,
|
|
|
|
struct android_log_transport_context* transp __unused,
|
|
|
|
char* buf, size_t len) {
|
|
|
|
const char cmd[] = "setPruneList ";
|
|
|
|
const size_t cmdlen = sizeof(cmd) - 1;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
if (strlen(buf) > (len - cmdlen)) {
|
|
|
|
return -ENOMEM; /* KISS */
|
|
|
|
}
|
|
|
|
memmove(buf + cmdlen, buf, len - cmdlen);
|
|
|
|
buf[len - 1] = '\0';
|
|
|
|
memcpy(buf, cmd, cmdlen);
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static void caught_signal(int signum __unused) {
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdOpen(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp) {
|
|
|
|
struct android_log_logger* logger;
|
|
|
|
struct sigaction ignore;
|
|
|
|
struct sigaction old_sigaction;
|
|
|
|
unsigned int old_alarm = 0;
|
|
|
|
char buffer[256], *cp, c;
|
|
|
|
int e, ret, remaining, sock;
|
|
|
|
|
|
|
|
if (!logger_list) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock = atomic_load(&transp->context.sock);
|
|
|
|
if (sock > 0) {
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_SEQPACKET);
|
|
|
|
if (sock == 0) {
|
|
|
|
/* Guarantee not file descriptor zero */
|
|
|
|
int newsock = socket_local_client(
|
|
|
|
"logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
|
|
|
|
close(sock);
|
|
|
|
sock = newsock;
|
|
|
|
}
|
|
|
|
if (sock <= 0) {
|
|
|
|
if ((sock == -1) && errno) {
|
|
|
|
return -errno;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
2017-03-09 17:09:43 +01:00
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose"
|
|
|
|
: "stream");
|
|
|
|
cp = buffer + strlen(buffer);
|
|
|
|
|
|
|
|
strcpy(cp, " lids");
|
|
|
|
cp += 5;
|
|
|
|
c = '=';
|
|
|
|
remaining = sizeof(buffer) - (cp - buffer);
|
|
|
|
logger_for_each(logger, logger_list) {
|
|
|
|
ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
|
|
|
|
ret = min(ret, remaining);
|
|
|
|
remaining -= ret;
|
|
|
|
cp += ret;
|
|
|
|
c = ',';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (logger_list->tail) {
|
|
|
|
ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
|
|
|
|
ret = min(ret, remaining);
|
|
|
|
remaining -= ret;
|
|
|
|
cp += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
|
|
|
|
if (logger_list->mode & ANDROID_LOG_WRAP) {
|
|
|
|
// ToDo: alternate API to allow timeout to be adjusted.
|
|
|
|
ret = snprintf(cp, remaining, " timeout=%u",
|
|
|
|
ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
|
|
|
|
ret = min(ret, remaining);
|
|
|
|
remaining -= ret;
|
|
|
|
cp += ret;
|
|
|
|
}
|
|
|
|
ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
|
|
|
|
logger_list->start.tv_sec, logger_list->start.tv_nsec);
|
|
|
|
ret = min(ret, remaining);
|
|
|
|
remaining -= ret;
|
|
|
|
cp += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (logger_list->pid) {
|
|
|
|
ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
|
|
|
|
ret = min(ret, remaining);
|
|
|
|
cp += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
|
|
|
|
/* Deal with an unresponsive logd */
|
|
|
|
memset(&ignore, 0, sizeof(ignore));
|
|
|
|
ignore.sa_handler = caught_signal;
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
/* particularily useful if tombstone is reporting for logd */
|
|
|
|
sigaction(SIGALRM, &ignore, &old_sigaction);
|
|
|
|
old_alarm = alarm(30);
|
|
|
|
}
|
|
|
|
ret = write(sock, buffer, cp - buffer);
|
|
|
|
e = errno;
|
|
|
|
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
|
|
|
|
if (e == EINTR) {
|
|
|
|
e = ETIMEDOUT;
|
|
|
|
}
|
|
|
|
alarm(old_alarm);
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret <= 0) {
|
|
|
|
close(sock);
|
|
|
|
if ((ret == -1) && e) {
|
|
|
|
return -e;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
2017-03-09 17:09:43 +01:00
|
|
|
if (ret == 0) {
|
|
|
|
return -EIO;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
2017-03-09 17:09:43 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
ret = atomic_exchange(&transp->context.sock, sock);
|
|
|
|
if ((ret > 0) && (ret != sock)) {
|
|
|
|
close(ret);
|
|
|
|
}
|
|
|
|
return sock;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read from the selected logs */
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdRead(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp,
|
|
|
|
struct log_msg* log_msg) {
|
|
|
|
int ret, e;
|
|
|
|
struct sigaction ignore;
|
|
|
|
struct sigaction old_sigaction;
|
|
|
|
unsigned int old_alarm = 0;
|
|
|
|
|
|
|
|
ret = logdOpen(logger_list, transp);
|
|
|
|
if (ret < 0) {
|
2016-03-01 22:45:42 +01:00
|
|
|
return ret;
|
2017-03-09 17:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(log_msg, 0, sizeof(*log_msg));
|
|
|
|
|
|
|
|
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
|
|
|
|
memset(&ignore, 0, sizeof(ignore));
|
|
|
|
ignore.sa_handler = caught_signal;
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
/* particularily useful if tombstone is reporting for logd */
|
|
|
|
sigaction(SIGALRM, &ignore, &old_sigaction);
|
|
|
|
old_alarm = alarm(30);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
|
|
|
|
ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
|
|
|
|
e = errno;
|
|
|
|
|
|
|
|
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
|
|
|
|
if ((ret == 0) || (e == EINTR)) {
|
|
|
|
e = EAGAIN;
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
alarm(old_alarm);
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret == -1) && e) {
|
|
|
|
return -e;
|
|
|
|
}
|
|
|
|
return ret;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
static int logdPoll(struct android_log_logger_list* logger_list,
|
|
|
|
struct android_log_transport_context* transp) {
|
|
|
|
struct pollfd p;
|
2016-03-01 22:45:42 +01:00
|
|
|
|
2017-03-09 17:09:43 +01:00
|
|
|
int ret = logdOpen(logger_list, transp);
|
|
|
|
if (ret < 0) {
|
2016-03-01 22:45:42 +01:00
|
|
|
return ret;
|
2017-03-09 17:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
p.fd = ret;
|
|
|
|
p.events = POLLIN;
|
|
|
|
ret = poll(&p, 1, 20);
|
|
|
|
if ((ret > 0) && !(p.revents & POLLIN)) {
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
if ((ret == -1) && errno) {
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
return ret;
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close all the logs */
|
2017-03-09 17:09:43 +01:00
|
|
|
static void logdClose(struct android_log_logger_list* logger_list __unused,
|
|
|
|
struct android_log_transport_context* transp) {
|
|
|
|
int sock = atomic_exchange(&transp->context.sock, -1);
|
|
|
|
if (sock > 0) {
|
|
|
|
close(sock);
|
|
|
|
}
|
2016-03-01 22:45:42 +01:00
|
|
|
}
|