• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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