/* * Copyright (C) 2020 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 "system_properties/prop_trace.h" #include #include #include #include #include #include "private/CachedProperty.h" #include "private/bionic_lock.h" #include "private/bionic_systrace.h" #include #include // For ATRACE_TAG_SYSPROP. #define PROP_TRACE_MSG_LENGTH 1024 static bool should_trace_prop(const char* prop_name) { // Should not trace kTraceTagsProp to avoid infinite recursion. // Because the following g_trace_enable_flags.Get() will get the property value // of kTraceTagsProp again, which in turn invokes should_trace_prop() here. if (prop_name == nullptr || !strcmp(prop_name, kTraceTagsProp)) { return false; } return should_trace(ATRACE_TAG_SYSPROP); } static void sysprop_trace_end() { int trace_marker_fd = get_trace_marker_fd(); if (trace_marker_fd == -1) { return; } TEMP_FAILURE_RETRY(write(trace_marker_fd, "E|", 2)); } static void get_sysprop_trace_end(const prop_info* pi, const char* prop_value, bool read_only = false) { const char* output_value; char message[PROP_TRACE_MSG_LENGTH]; if (read_only) { if (pi->is_long()) { output_value = pi->long_value(); } else { output_value = pi->value; } } else { output_value = prop_value; } snprintf(message, sizeof(message), "prop_get: %s, value: %s", pi->name, output_value ? output_value : "null_value"); output_trace(message, 'E'); // 'E' for end. } SyspropTrace::SyspropTrace(const char* prop_name, const char* prop_value, const prop_info* pi, PropertyAction action) : prop_name_(prop_name), prop_value_(prop_value), prop_info_(pi), prop_action_(action), output_trace_(false) { if (!should_trace_prop(prop_name)) { return; } char message[PROP_TRACE_MSG_LENGTH]; if (prop_action_ == PropertyAction::kPropertyFind) { snprintf(message, sizeof(message), "prop_find: %s", prop_name_); } else if (prop_action_ == PropertyAction::kPropertySet) { snprintf(message, sizeof(message), "prop_set: %s, value: %s", prop_name_, prop_value_ ? prop_value_ : "null_value"); } else { // For property get, the prop_value_ will be resolved then printed in the destructor. snprintf(message, sizeof(message), "prop_get: %s", prop_name_); } output_trace(message, 'B'); // 'B' for begin. output_trace_ = true; } SyspropTrace::~SyspropTrace() { if (!output_trace_) { return; } if (prop_action_ == PropertyAction::kPropertyFind || prop_action_ == PropertyAction::kPropertySet) { sysprop_trace_end(); } else if (prop_action_ == PropertyAction::kPropertyGetReadOnly) { get_sysprop_trace_end(prop_info_, prop_value_, true /* read_only */); } else if (prop_action_ == PropertyAction::kPropertyGetReadWrite) { get_sysprop_trace_end(prop_info_, prop_value_, false /* read_only */); } output_trace_ = false; }