summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEarl Ou2016-11-22 03:04:44 -0600
committerEarl Ou2017-08-03 02:16:44 -0500
commite4030384c40a7889fbf0c18ea71335567deae342 (patch)
tree230c959d5b4bdc6f525f93b0d2098a48f7411724 /libcutils/trace-dev.inc
parent5c655991f51e63f4264619293b393a2c6bddb1fa (diff)
downloadplatform-system-core-e4030384c40a7889fbf0c18ea71335567deae342.tar.gz
platform-system-core-e4030384c40a7889fbf0c18ea71335567deae342.tar.xz
platform-system-core-e4030384c40a7889fbf0c18ea71335567deae342.zip
libcutils: write trace event into socket in container
When Android is running in a container, ftrace trace_marker may be disabled, e.g. Chrome OS verified mode. To enable trace, a socket is created for everyone to send trace event. Modify libcutils so apps using it can write trace to the socket. To achieve this goal without touching code for normal device, trace-container.c is created for code specific to container. Shared code between trace-dev.c and trace-container.c is moved to local trace-dev.h. Note that to avoid sharing FDs across different processes, Zygote closes FD and reopen it to /dev/null if it is a socket. Therefore, we need to manually close FD and reopen it again after forking. This is done in the atrace_set_tracing_enabled as Zygote also use it to clear flags during forking. Related change: - http://crrev.com/2400163003 (Chromium) - http://ag/2028075 (Android system/core) - http://ag/1738271 (Android device/google/cheets2) Bug: 29776474, 62410809 Test: run chrome://tracing and see data from the host side. Change-Id: I3fe969e284b972c28e4f32f23cd948aaea61a043
Diffstat (limited to 'libcutils/trace-dev.inc')
-rw-r--r--libcutils/trace-dev.inc173
1 files changed, 173 insertions, 0 deletions
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
new file mode 100644
index 000000000..f32330a4c
--- /dev/null
+++ b/libcutils/trace-dev.inc
@@ -0,0 +1,173 @@
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#ifndef __TRACE_DEV_INC
18#define __TRACE_DEV_INC
19
20#define LOG_TAG "cutils-trace"
21
22#include <errno.h>
23#include <fcntl.h>
24#include <limits.h>
25#include <pthread.h>
26#include <stdatomic.h>
27#include <stdbool.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/types.h>
31
32#include <cutils/compiler.h>
33#include <cutils/properties.h>
34#include <cutils/trace.h>
35#include <log/log.h>
36#include <log/log_properties.h>
37
38/**
39 * Maximum size of a message that can be logged to the trace buffer.
40 * Note this message includes a tag, the pid, and the string given as the name.
41 * Names should be kept short to get the most use of the trace buffer.
42 */
43#define ATRACE_MESSAGE_LENGTH 1024
44
45atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(false);
46int atrace_marker_fd = -1;
47uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY;
48static bool atrace_is_debuggable = false;
49static atomic_bool atrace_is_enabled = ATOMIC_VAR_INIT(true);
50static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER;
51
52// Set whether this process is debuggable, which determines whether
53// application-level tracing is allowed when the ro.debuggable system property
54// is not set to '1'.
55void atrace_set_debuggable(bool debuggable)
56{
57 atrace_is_debuggable = debuggable;
58 atrace_update_tags();
59}
60
61// Check whether the given command line matches one of the comma-separated
62// values listed in the app_cmdlines property.
63static bool atrace_is_cmdline_match(const char* cmdline)
64{
65 int count = property_get_int32("debug.atrace.app_number", 0);
66
67 char buf[PROPERTY_KEY_MAX];
68 char value[PROPERTY_VALUE_MAX];
69
70 for (int i = 0; i < count; i++) {
71 snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
72 property_get(buf, value, "");
73 if (strcmp(value, cmdline) == 0) {
74 return true;
75 }
76 }
77
78 return false;
79}
80
81// Determine whether application-level tracing is enabled for this process.
82static bool atrace_is_app_tracing_enabled()
83{
84 bool sys_debuggable = __android_log_is_debuggable();
85 bool result = false;
86
87 if (sys_debuggable || atrace_is_debuggable) {
88 // Check whether tracing is enabled for this process.
89 FILE * file = fopen("/proc/self/cmdline", "re");
90 if (file) {
91 char cmdline[4096];
92 if (fgets(cmdline, sizeof(cmdline), file)) {
93 result = atrace_is_cmdline_match(cmdline);
94 } else {
95 ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
96 }
97 fclose(file);
98 } else {
99 ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
100 errno);
101 }
102 }
103
104 return result;
105}
106
107// Read the sysprop and return the value tags should be set to
108static uint64_t atrace_get_property()
109{
110 char value[PROPERTY_VALUE_MAX];
111 char *endptr;
112 uint64_t tags;
113
114 property_get("debug.atrace.tags.enableflags", value, "0");
115 errno = 0;
116 tags = strtoull(value, &endptr, 0);
117 if (value[0] == '\0' || *endptr != '\0') {
118 ALOGE("Error parsing trace property: Not a number: %s", value);
119 return 0;
120 } else if (errno == ERANGE || tags == ULLONG_MAX) {
121 ALOGE("Error parsing trace property: Number too large: %s", value);
122 return 0;
123 }
124
125 // Only set the "app" tag if this process was selected for app-level debug
126 // tracing.
127 if (atrace_is_app_tracing_enabled()) {
128 tags |= ATRACE_TAG_APP;
129 } else {
130 tags &= ~ATRACE_TAG_APP;
131 }
132
133 return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
134}
135
136// Update tags if tracing is ready. Useful as a sysprop change callback.
137void atrace_update_tags()
138{
139 uint64_t tags;
140 if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
141 if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
142 tags = atrace_get_property();
143 pthread_mutex_lock(&atrace_tags_mutex);
144 atrace_enabled_tags = tags;
145 pthread_mutex_unlock(&atrace_tags_mutex);
146 } else {
147 // Tracing is disabled for this process, so we simply don't
148 // initialize the tags.
149 pthread_mutex_lock(&atrace_tags_mutex);
150 atrace_enabled_tags = ATRACE_TAG_NOT_READY;
151 pthread_mutex_unlock(&atrace_tags_mutex);
152 }
153 }
154}
155
156#define WRITE_MSG(format_begin, format_end, name, value) { \
157 char buf[ATRACE_MESSAGE_LENGTH]; \
158 int pid = getpid(); \
159 int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
160 name, value); \
161 if (len >= (int) sizeof(buf)) { \
162 /* Given the sizeof(buf), and all of the current format buffers, \
163 * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
164 int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
165 /* Truncate the name to make the message fit. */ \
166 ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
167 len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
168 name_len, name, value); \
169 } \
170 write(atrace_marker_fd, buf, len); \
171}
172
173#endif // __TRACE_DEV_INC