| /* | 
 |  * Copyright (C) 2018 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 "src/profiling/memory/system_property.h" | 
 |  | 
 | #include "perfetto/base/logging.h" | 
 | #include "perfetto/ext/base/utils.h" | 
 |  | 
 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) | 
 | #include <sys/system_properties.h> | 
 | #endif | 
 |  | 
 | namespace perfetto { | 
 | namespace profiling { | 
 |  | 
 | SystemProperties::Handle::Handle(Handle&& other) noexcept { | 
 |   system_properties_ = other.system_properties_; | 
 |   property_ = std::move(other.property_); | 
 |   all_ = other.all_; | 
 |   other.system_properties_ = nullptr; | 
 | } | 
 |  | 
 | SystemProperties::Handle& SystemProperties::Handle::operator=( | 
 |     Handle&& other) noexcept { | 
 |   // Construct this temporary because the RHS could be an lvalue cast to an | 
 |   // rvalue reference whose lifetime we do not know. | 
 |   Handle tmp(std::move(other)); | 
 |   using std::swap; | 
 |   swap(*this, tmp); | 
 |   return *this; | 
 | } | 
 |  | 
 | SystemProperties::Handle::Handle(SystemProperties* system_properties) | 
 |     : system_properties_(system_properties), all_(true) {} | 
 |  | 
 | SystemProperties::Handle::Handle(SystemProperties* system_properties, | 
 |                                  std::string property) | 
 |     : system_properties_(system_properties), property_(std::move(property)) {} | 
 |  | 
 | SystemProperties::Handle::~Handle() { | 
 |   if (system_properties_) { | 
 |     if (all_) | 
 |       system_properties_->UnsetAll(); | 
 |     else | 
 |       system_properties_->UnsetProperty(property_); | 
 |   } | 
 | } | 
 |  | 
 | SystemProperties::Handle::operator bool() { | 
 |   return system_properties_ != nullptr; | 
 | } | 
 |  | 
 | SystemProperties::Handle SystemProperties::SetProperty(std::string name) { | 
 |   auto it = properties_.find(name); | 
 |   if (it == properties_.end()) { | 
 |     if (!SetAndroidProperty("heapprofd.enable." + name, "1")) | 
 |       return Handle(nullptr); | 
 |     if (properties_.size() == 1 || alls_ == 0) { | 
 |       if (!SetAndroidProperty("heapprofd.enable", "1")) | 
 |         return Handle(nullptr); | 
 |     } | 
 |     properties_.emplace(name, 1); | 
 |   } else { | 
 |     it->second++; | 
 |   } | 
 |   return Handle(this, std::move(name)); | 
 | } | 
 |  | 
 | SystemProperties::Handle SystemProperties::SetAll() { | 
 |   if (alls_ == 0) { | 
 |     if (!SetAndroidProperty("heapprofd.enable", "all")) | 
 |       return Handle(nullptr); | 
 |   } | 
 |   alls_++; | 
 |   return Handle(this); | 
 | } | 
 |  | 
 | // This is conditionally noreturn, so disable the warning. | 
 | #pragma GCC diagnostic push | 
 | #if PERFETTO_DCHECK_IS_ON() | 
 | #pragma GCC diagnostic ignored "-Wmissing-noreturn" | 
 | #endif | 
 |  | 
 | // static | 
 | void SystemProperties::ResetHeapprofdProperties() { | 
 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) | 
 |   int r = __system_property_foreach( | 
 |       [](const prop_info* pi, void*) { | 
 |         __system_property_read_callback( | 
 |             pi, | 
 |             [](void*, const char* name, const char*, uint32_t) { | 
 |               constexpr char kDebugModePropName[] = "heapprofd.userdebug.mode"; | 
 |  | 
 |               // Unset everything starting with "heapprofd.", except for the | 
 |               // property stating which mode to use on debug builds. | 
 |               const char* found = strstr(name, "heapprofd."); | 
 |               if (found == name && strncmp(name, kDebugModePropName, | 
 |                                            strlen(kDebugModePropName))) { | 
 |                 int ret = __system_property_set(name, ""); | 
 |                 PERFETTO_DCHECK(ret == 0); | 
 |               } | 
 |             }, | 
 |             nullptr); | 
 |       }, | 
 |       nullptr); | 
 |   PERFETTO_DCHECK(r == 0); | 
 | #else | 
 |   PERFETTO_DFATAL_OR_ELOG( | 
 |       "Cannot ResetHeapprofdProperties on out-of-tree builds."); | 
 | #endif | 
 | } | 
 |  | 
 | #pragma GCC diagnostic pop | 
 |  | 
 | SystemProperties::~SystemProperties() { | 
 |   PERFETTO_DCHECK(alls_ == 0 && properties_.empty()); | 
 | } | 
 |  | 
 | bool SystemProperties::SetAndroidProperty(const std::string& name, | 
 |                                           const std::string& value) { | 
 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) | 
 |   return __system_property_set(name.c_str(), value.c_str()) == 0; | 
 | #else | 
 |   // Allow this to be mocked out for tests on other platforms. | 
 |   base::ignore_result(name); | 
 |   base::ignore_result(value); | 
 |   PERFETTO_FATAL("Properties can only be set on Android."); | 
 | #endif | 
 | } | 
 |  | 
 | void SystemProperties::UnsetProperty(const std::string& name) { | 
 |   auto it = properties_.find(name); | 
 |   if (it == properties_.end()) { | 
 |     PERFETTO_DFATAL_OR_ELOG("Unsetting unknown property."); | 
 |     return; | 
 |   } | 
 |   if (--(it->second) == 0) { | 
 |     properties_.erase(it); | 
 |     SetAndroidProperty("heapprofd.enable." + name, ""); | 
 |     if (properties_.empty() && alls_ == 0) | 
 |       SetAndroidProperty("heapprofd.enable", ""); | 
 |   } | 
 | } | 
 |  | 
 | void SystemProperties::UnsetAll() { | 
 |   if (--alls_ == 0) { | 
 |     if (properties_.empty()) | 
 |       SetAndroidProperty("heapprofd.enable", ""); | 
 |     else | 
 |       SetAndroidProperty("heapprofd.enable", "1"); | 
 |   } | 
 | } | 
 |  | 
 | void swap(SystemProperties::Handle& a, SystemProperties::Handle& b) { | 
 |   using std::swap; | 
 |   swap(a.system_properties_, b.system_properties_); | 
 |   swap(a.property_, b.property_); | 
 |   swap(a.all_, b.all_); | 
 | } | 
 |  | 
 | }  // namespace profiling | 
 | }  // namespace perfetto |