| Bowgo Tsai | d0ecf0b | 2020-04-13 13:07:43 +0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2020 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 "system_properties/prop_trace.h" | 
 | 18 |  | 
 | 19 | #include <errno.h> | 
 | 20 | #include <fcntl.h> | 
 | 21 | #include <stdio.h> | 
 | 22 | #include <stdlib.h> | 
 | 23 | #include <string.h> | 
 | 24 |  | 
 | 25 | #include "private/CachedProperty.h" | 
 | 26 | #include "private/bionic_lock.h" | 
 | 27 | #include "private/bionic_systrace.h" | 
 | 28 |  | 
 | 29 | #include <async_safe/log.h> | 
 | 30 | #include <cutils/trace.h>  // For ATRACE_TAG_SYSPROP. | 
 | 31 |  | 
 | 32 | #define PROP_TRACE_MSG_LENGTH 1024 | 
 | 33 |  | 
 | 34 | static bool should_trace_prop(const char* prop_name) { | 
 | 35 |   // Should not trace kTraceTagsProp to avoid infinite recursion. | 
 | 36 |   // Because the following g_trace_enable_flags.Get() will get the property value | 
 | 37 |   // of kTraceTagsProp again, which in turn invokes should_trace_prop() here. | 
 | 38 |   if (prop_name == nullptr || !strcmp(prop_name, kTraceTagsProp)) { | 
 | 39 |     return false; | 
 | 40 |   } | 
 | 41 |  | 
 | 42 |   return should_trace(ATRACE_TAG_SYSPROP); | 
 | 43 | } | 
 | 44 |  | 
 | 45 | static void sysprop_trace_end() { | 
 | 46 |   int trace_marker_fd = get_trace_marker_fd(); | 
 | 47 |   if (trace_marker_fd == -1) { | 
 | 48 |     return; | 
 | 49 |   } | 
 | 50 |  | 
 | 51 |   TEMP_FAILURE_RETRY(write(trace_marker_fd, "E|", 2)); | 
 | 52 | } | 
 | 53 |  | 
 | 54 | static void get_sysprop_trace_end(const prop_info* pi, const char* prop_value, | 
 | 55 |                                   bool read_only = false) { | 
 | 56 |   const char* output_value; | 
 | 57 |   char message[PROP_TRACE_MSG_LENGTH]; | 
 | 58 |  | 
 | 59 |   if (read_only) { | 
 | 60 |     if (pi->is_long()) { | 
 | 61 |       output_value = pi->long_value(); | 
 | 62 |     } else { | 
 | 63 |       output_value = pi->value; | 
 | 64 |     } | 
 | 65 |   } else { | 
 | 66 |     output_value = prop_value; | 
 | 67 |   } | 
 | 68 |  | 
 | 69 |   snprintf(message, sizeof(message), "prop_get: %s, value: %s", pi->name, | 
 | 70 |            output_value ? output_value : "null_value"); | 
 | 71 |   output_trace(message, 'E');  // 'E' for end. | 
 | 72 | } | 
 | 73 |  | 
 | 74 | SyspropTrace::SyspropTrace(const char* prop_name, const char* prop_value, const prop_info* pi, | 
 | 75 |                            PropertyAction action) | 
 | 76 |     : prop_name_(prop_name), | 
 | 77 |       prop_value_(prop_value), | 
 | 78 |       prop_info_(pi), | 
 | 79 |       prop_action_(action), | 
 | 80 |       output_trace_(false) { | 
 | 81 |   if (!should_trace_prop(prop_name)) { | 
 | 82 |     return; | 
 | 83 |   } | 
 | 84 |  | 
 | 85 |   char message[PROP_TRACE_MSG_LENGTH]; | 
 | 86 |   if (prop_action_ == PropertyAction::kPropertyFind) { | 
 | 87 |     snprintf(message, sizeof(message), "prop_find: %s", prop_name_); | 
 | 88 |   } else if (prop_action_ == PropertyAction::kPropertySet) { | 
 | 89 |     snprintf(message, sizeof(message), "prop_set: %s, value: %s", prop_name_, | 
 | 90 |              prop_value_ ? prop_value_ : "null_value"); | 
 | 91 |   } else { | 
 | 92 |     // For property get, the prop_value_ will be resolved then printed in the destructor. | 
 | 93 |     snprintf(message, sizeof(message), "prop_get: %s", prop_name_); | 
 | 94 |   } | 
 | 95 |  | 
 | 96 |   output_trace(message, 'B');  // 'B' for begin. | 
 | 97 |   output_trace_ = true; | 
 | 98 | } | 
 | 99 |  | 
 | 100 | SyspropTrace::~SyspropTrace() { | 
 | 101 |   if (!output_trace_) { | 
 | 102 |     return; | 
 | 103 |   } | 
 | 104 |   if (prop_action_ == PropertyAction::kPropertyFind || | 
 | 105 |       prop_action_ == PropertyAction::kPropertySet) { | 
 | 106 |     sysprop_trace_end(); | 
 | 107 |   } else if (prop_action_ == PropertyAction::kPropertyGetReadOnly) { | 
 | 108 |     get_sysprop_trace_end(prop_info_, prop_value_, true /* read_only */); | 
 | 109 |   } else if (prop_action_ == PropertyAction::kPropertyGetReadWrite) { | 
 | 110 |     get_sysprop_trace_end(prop_info_, prop_value_, false /* read_only */); | 
 | 111 |   } | 
 | 112 |   output_trace_ = false; | 
 | 113 | } |