1/* 2 * Copyright (C) 2014 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#include <cutils/trace.h> 18#include <errno.h> 19#include <fcntl.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23 24#include "private/bionic_lock.h" 25#include "private/bionic_systrace.h" 26#include "private/libc_logging.h" 27 28#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 29#include <sys/_system_properties.h> 30 31#define WRITE_OFFSET 32 32 33constexpr char SYSTRACE_PROPERTY_NAME[] = "debug.atrace.tags.enableflags"; 34 35static Lock g_lock; 36static const prop_info* g_pinfo; 37static uint32_t g_serial = -1; 38static uint64_t g_tags; 39static int g_trace_marker_fd = -1; 40 41static bool should_trace() { 42 bool result = false; 43 g_lock.lock(); 44 // If g_pinfo is null, this means that systrace hasn't been run and it's safe to 45 // assume that no trace writing will need to take place. However, to avoid running 46 // this costly find check each time, we set it to a non-tracing value so that next 47 // time, it will just check the serial to see if the value has been changed. 48 // this function also deals with the bootup case, during which the call to property 49 // set will fail if the property server hasn't yet started. 50 if (g_pinfo == NULL) { 51 g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME); 52 if (g_pinfo == NULL) { 53 __system_property_set(SYSTRACE_PROPERTY_NAME, "0"); 54 g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME); 55 } 56 } 57 if (g_pinfo != NULL) { 58 // Find out which tags have been enabled on the command line and set 59 // the value of tags accordingly. If the value of the property changes, 60 // the serial will also change, so the costly system_property_read function 61 // can be avoided by calling the much cheaper system_property_serial 62 // first. The values within pinfo may change, but its location is guaranteed 63 // not to move. 64 uint32_t cur_serial = __system_property_serial(g_pinfo); 65 if (cur_serial != g_serial) { 66 g_serial = cur_serial; 67 char value[PROP_VALUE_MAX]; 68 __system_property_read(g_pinfo, 0, value); 69 g_tags = strtoull(value, NULL, 0); 70 } 71 result = ((g_tags & ATRACE_TAG_BIONIC) != 0); 72 } 73 g_lock.unlock(); 74 return result; 75} 76 77static int get_trace_marker_fd() { 78 g_lock.lock(); 79 if (g_trace_marker_fd == -1) { 80 g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY); 81 } 82 g_lock.unlock(); 83 return g_trace_marker_fd; 84} 85 86ScopedTrace::ScopedTrace(const char* message) { 87 if (!should_trace()) { 88 return; 89 } 90 91 int trace_marker_fd = get_trace_marker_fd(); 92 if (trace_marker_fd == -1) { 93 return; 94 } 95 96 // If bionic tracing has been enabled, then write the message to the 97 // kernel trace_marker. 98 int length = strlen(message); 99 char buf[length + WRITE_OFFSET]; 100 size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message); 101 102 // Tracing may stop just after checking property and before writing the message. 103 // So the write is acceptable to fail. See b/20666100. 104 TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len)); 105} 106 107ScopedTrace::~ScopedTrace() { 108 if (!should_trace()) { 109 return; 110 } 111 112 int trace_marker_fd = get_trace_marker_fd(); 113 if (trace_marker_fd == -1) { 114 return; 115 } 116 117 TEMP_FAILURE_RETRY(write(trace_marker_fd, "E", 1)); 118} 119