summaryrefslogtreecommitdiff
path: root/libc/system_properties/prop_trace.cpp
blob: ac7ff941447a70abad749c7f97d8616b0fbde6e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "private/CachedProperty.h"
#include "private/bionic_lock.h"
#include "private/bionic_systrace.h"

#include <async_safe/log.h>
#include <cutils/trace.h>  // 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;
}