/* * 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 #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