blob: ac7ff941447a70abad749c7f97d8616b0fbde6e8 [file] [log] [blame]
Bowgo Tsaid0ecf0b2020-04-13 13:07:43 +08001/*
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
34static 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
45static 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
54static 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
74SyspropTrace::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
100SyspropTrace::~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}