1 /*
2 * Copyright (C) 2018 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 "src/profiling/memory/system_property.h"
18
19 #include "perfetto/base/logging.h"
20
21 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
22 #include <sys/system_properties.h>
23 #endif
24
25 namespace perfetto {
26 namespace profiling {
27
Handle(Handle && other)28 SystemProperties::Handle::Handle(Handle&& other) {
29 system_properties_ = other.system_properties_;
30 property_ = std::move(other.property_);
31 all_ = other.all_;
32 other.system_properties_ = nullptr;
33 }
34
operator =(Handle && other)35 SystemProperties::Handle& SystemProperties::Handle::operator=(Handle&& other) {
36 // Construct this temporary because the RHS could be an lvalue cast to an
37 // rvalue reference whose lifetime we do not know.
38 Handle tmp(std::move(other));
39 using std::swap;
40 swap(*this, tmp);
41 return *this;
42 }
43
Handle(SystemProperties * system_properties)44 SystemProperties::Handle::Handle(SystemProperties* system_properties)
45 : system_properties_(system_properties), all_(true) {}
46
Handle(SystemProperties * system_properties,std::string property)47 SystemProperties::Handle::Handle(SystemProperties* system_properties,
48 std::string property)
49 : system_properties_(system_properties), property_(std::move(property)) {}
50
~Handle()51 SystemProperties::Handle::~Handle() {
52 if (system_properties_) {
53 if (all_)
54 system_properties_->UnsetAll();
55 else
56 system_properties_->UnsetProperty(property_);
57 }
58 }
59
operator bool()60 SystemProperties::Handle::operator bool() {
61 return system_properties_ != nullptr;
62 }
63
SetProperty(std::string name)64 SystemProperties::Handle SystemProperties::SetProperty(std::string name) {
65 auto it = properties_.find(name);
66 if (it == properties_.end()) {
67 if (!SetAndroidProperty("heapprofd.enable." + name, "1"))
68 return Handle(nullptr);
69 if (properties_.size() == 1 || alls_ == 0) {
70 if (!SetAndroidProperty("heapprofd.enable", "1"))
71 return Handle(nullptr);
72 }
73 properties_.emplace(name, 1);
74 } else {
75 it->second++;
76 }
77 return Handle(this, std::move(name));
78 }
79
SetAll()80 SystemProperties::Handle SystemProperties::SetAll() {
81 if (alls_ == 0) {
82 if (!SetAndroidProperty("heapprofd.enable", "all"))
83 return Handle(nullptr);
84 }
85 alls_++;
86 return Handle(this);
87 }
88
89 // This is conditionally noreturn, so disable the warning.
90 #pragma GCC diagnostic push
91 #if PERFETTO_DCHECK_IS_ON()
92 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
93 #endif
94
95 // static
ResetHeapprofdProperties()96 void SystemProperties::ResetHeapprofdProperties() {
97 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
98 int r = __system_property_foreach(
99 [](const prop_info* pi, void*) {
100 __system_property_read_callback(
101 pi,
102 [](void*, const char* name, const char*, uint32_t) {
103 constexpr char kDebugModePropName[] = "heapprofd.userdebug.mode";
104
105 // Unset everything starting with "heapprofd.", except for the
106 // property stating which mode to use on debug builds.
107 const char* found = strstr(name, "heapprofd.");
108 if (found == name && strncmp(name, kDebugModePropName,
109 strlen(kDebugModePropName))) {
110 int ret = __system_property_set(name, "");
111 PERFETTO_DCHECK(ret == 0);
112 }
113 },
114 nullptr);
115 },
116 nullptr);
117 PERFETTO_DCHECK(r == 0);
118 #else
119 PERFETTO_DFATAL("Cannot ResetHeapprofdProperties on out-of-tree builds.");
120 #endif
121 }
122
123 #pragma GCC diagnostic pop
124
~SystemProperties()125 SystemProperties::~SystemProperties() {
126 PERFETTO_DCHECK(alls_ == 0 && properties_.empty());
127 }
128
SetAndroidProperty(const std::string & name,const std::string & value)129 bool SystemProperties::SetAndroidProperty(const std::string& name,
130 const std::string& value) {
131 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
132 return __system_property_set(name.c_str(), value.c_str()) == 0;
133 #else
134 // Allow this to be mocked out for tests on other platforms.
135 base::ignore_result(name);
136 base::ignore_result(value);
137 PERFETTO_FATAL("Properties can only be set on Android.");
138 #endif
139 }
140
UnsetProperty(const std::string & name)141 void SystemProperties::UnsetProperty(const std::string& name) {
142 auto it = properties_.find(name);
143 if (it == properties_.end()) {
144 PERFETTO_DFATAL("Unsetting unknown property.");
145 return;
146 }
147 if (--(it->second) == 0) {
148 properties_.erase(it);
149 SetAndroidProperty("heapprofd.enable." + name, "");
150 if (properties_.empty() && alls_ == 0)
151 SetAndroidProperty("heapprofd.enable", "");
152 }
153 }
154
UnsetAll()155 void SystemProperties::UnsetAll() {
156 if (--alls_ == 0) {
157 if (properties_.empty())
158 SetAndroidProperty("heapprofd.enable", "");
159 else
160 SetAndroidProperty("heapprofd.enable", "1");
161 }
162 }
163
swap(SystemProperties::Handle & a,SystemProperties::Handle & b)164 void swap(SystemProperties::Handle& a, SystemProperties::Handle& b) {
165 using std::swap;
166 swap(a.system_properties_, b.system_properties_);
167 swap(a.property_, b.property_);
168 swap(a.all_, b.all_);
169 }
170
171 } // namespace profiling
172 } // namespace perfetto
173