// Copyright (C) 2019 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. // // This file is automatically generated by gen_amalgamated. Do not edit. // gen_amalgamated: predefined macros #if !defined(PERFETTO_IMPLEMENTATION) #define PERFETTO_IMPLEMENTATION #endif #include "perfetto.h" // gen_amalgamated begin source: src/base/android_utils.cc // gen_amalgamated begin header: include/perfetto/ext/base/android_utils.h /* * Copyright (C) 2021 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ #define INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ #include // gen_amalgamated expanded: #include "perfetto/base/build_config.h" namespace perfetto { namespace base { #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) // Returns the value of the Android system property named `name`. If the // property does not exist, returns an empty string (a non-existing property is // the same as a property with an empty value for this API). std::string GetAndroidProp(const char* name); #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ /* * Copyright (C) 2021 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. */ // gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h" // gen_amalgamated expanded: #include "perfetto/base/build_config.h" #include #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) #include #endif // gen_amalgamated expanded: #include "perfetto/base/compiler.h" // gen_amalgamated expanded: #include "perfetto/base/logging.h" namespace perfetto { namespace base { #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) std::string GetAndroidProp(const char* name) { std::string ret; #if __ANDROID_API__ >= 26 const prop_info* pi = __system_property_find(name); if (!pi) { return ret; } __system_property_read_callback( pi, [](void* dst_void, const char*, const char* value, uint32_t) { std::string& dst = *static_cast(dst_void); dst = value; }, &ret); #else // __ANDROID_API__ < 26 char value_buf[PROP_VALUE_MAX]; int len = __system_property_get(name, value_buf); if (len > 0 && static_cast(len) < sizeof(value_buf)) { ret = std::string(value_buf, static_cast(len)); } #endif return ret; } #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) } // namespace base } // namespace perfetto // gen_amalgamated begin source: src/base/base64.cc // gen_amalgamated begin header: include/perfetto/ext/base/base64.h // gen_amalgamated begin header: include/perfetto/ext/base/optional.h /* * 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_OPTIONAL_H_ #define INCLUDE_PERFETTO_EXT_BASE_OPTIONAL_H_ #include #include #include // gen_amalgamated expanded: #include "perfetto/base/logging.h" namespace perfetto { namespace base { // Specification: // http://en.cppreference.com/w/cpp/utility/optional/in_place_t struct in_place_t {}; // Specification: // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t struct nullopt_t { constexpr explicit nullopt_t(int) {} }; // Specification: // http://en.cppreference.com/w/cpp/utility/optional/in_place constexpr in_place_t in_place = {}; // Specification: // http://en.cppreference.com/w/cpp/utility/optional/nullopt constexpr nullopt_t nullopt(0); // Forward declaration, which is referred by following helpers. template class Optional; namespace internal { template ::value> struct OptionalStorageBase { // Initializing |empty_| here instead of using default member initializing // to avoid errors in g++ 4.8. constexpr OptionalStorageBase() : empty_('\0') {} template constexpr explicit OptionalStorageBase(in_place_t, Args&&... args) : is_populated_(true), value_(std::forward(args)...) {} // When T is not trivially destructible we must call its // destructor before deallocating its memory. // Note that this hides the (implicitly declared) move constructor, which // would be used for constexpr move constructor in OptionalStorage. // It is needed iff T is trivially move constructible. However, the current // is_trivially_{copy,move}_constructible implementation requires // is_trivially_destructible (which looks a bug, cf: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not // necessary for this case at the moment. Please see also the destructor // comment in "is_trivially_destructible = true" specialization below. ~OptionalStorageBase() { if (is_populated_) value_.~T(); } template void Init(Args&&... args) { PERFETTO_DCHECK(!is_populated_); ::new (&value_) T(std::forward(args)...); is_populated_ = true; } bool is_populated_ = false; union { // |empty_| exists so that the union will always be initialized, even when // it doesn't contain a value. Union members must be initialized for the // constructor to be 'constexpr'. char empty_; T value_; }; }; template struct OptionalStorageBase { // Initializing |empty_| here instead of using default member initializing // to avoid errors in g++ 4.8. constexpr OptionalStorageBase() : empty_('\0') {} template constexpr explicit OptionalStorageBase(in_place_t, Args&&... args) : is_populated_(true), value_(std::forward(args)...) {} // When T is trivially destructible (i.e. its destructor does nothing) there // is no need to call it. Implicitly defined destructor is trivial, because // both members (bool and union containing only variants which are trivially // destructible) are trivially destructible. // Explicitly-defaulted destructor is also trivial, but do not use it here, // because it hides the implicit move constructor. It is needed to implement // constexpr move constructor in OptionalStorage iff T is trivially move // constructible. Note that, if T is trivially move constructible, the move // constructor of OptionalStorageBase is also implicitly defined and it is // trivially move constructor. If T is not trivially move constructible, // "not declaring move constructor without destructor declaration" here means // "delete move constructor", which works because any move constructor of // OptionalStorage will not refer to it in that case. template void Init(Args&&... args) { PERFETTO_DCHECK(!is_populated_); ::new (&value_) T(std::forward(args)...); is_populated_ = true; } bool is_populated_ = false; union { // |empty_| exists so that the union will always be initialized, even when // it doesn't contain a value. Union members must be initialized for the // constructor to be 'constexpr'. char empty_; T value_; }; }; // Implement conditional constexpr copy and move constructors. These are // constexpr if is_trivially_{copy,move}_constructible::value is true // respectively. If each is true, the corresponding constructor is defined as // "= default;", which generates a constexpr constructor (In this case, // the condition of constexpr-ness is satisfied because the base class also has // compiler generated constexpr {copy,move} constructors). Note that // placement-new is prohibited in constexpr. template ::value> struct OptionalStorage : OptionalStorageBase { // This is no trivially {copy,move} constructible case. Other cases are // defined below as specializations. // Accessing the members of template base class requires explicit // declaration. using OptionalStorageBase::is_populated_; using OptionalStorageBase::value_; using OptionalStorageBase::Init; // Inherit constructors (specifically, the in_place constructor). using OptionalStorageBase::OptionalStorageBase; // User defined constructor deletes the default constructor. // Define it explicitly. OptionalStorage() = default; OptionalStorage(const OptionalStorage& other) : OptionalStorageBase() { if (other.is_populated_) Init(other.value_); } OptionalStorage(OptionalStorage&& other) noexcept( std::is_nothrow_move_constructible::value) { if (other.is_populated_) Init(std::move(other.value_)); } }; template struct OptionalStorage : OptionalStorageBase { using OptionalStorageBase::is_populated_; using OptionalStorageBase::value_; using OptionalStorageBase::Init; using OptionalStorageBase::OptionalStorageBase; OptionalStorage() = default; OptionalStorage(const OptionalStorage& other) = default; OptionalStorage(OptionalStorage&& other) noexcept( std::is_nothrow_move_constructible::value) { if (other.is_populated_) Init(std::move(other.value_)); } }; // Base class to support conditionally usable copy-/move- constructors // and assign operators. template class OptionalBase { // This class provides implementation rather than public API, so everything // should be hidden. Often we use composition, but we cannot in this case // because of C++ language restriction. protected: constexpr OptionalBase() = default; constexpr OptionalBase(const OptionalBase& other) = default; constexpr OptionalBase(OptionalBase&& other) = default; template constexpr explicit OptionalBase(in_place_t, Args&&... args) : storage_(in_place, std::forward(args)...) {} // Implementation of converting constructors. template explicit OptionalBase(const OptionalBase& other) { if (other.storage_.is_populated_) storage_.Init(other.storage_.value_); } template explicit OptionalBase(OptionalBase&& other) { if (other.storage_.is_populated_) storage_.Init(std::move(other.storage_.value_)); } ~OptionalBase() = default; OptionalBase& operator=(const OptionalBase& other) { CopyAssign(other); return *this; } OptionalBase& operator=(OptionalBase&& other) noexcept( std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) { MoveAssign(std::move(other)); return *this; } template void CopyAssign(const OptionalBase& other) { if (other.storage_.is_populated_) InitOrAssign(other.storage_.value_); else FreeIfNeeded(); } template void MoveAssign(OptionalBase&& other) { if (other.storage_.is_populated_) InitOrAssign(std::move(other.storage_.value_)); else FreeIfNeeded(); } template void InitOrAssign(U&& value) { if (storage_.is_populated_) storage_.value_ = std::forward(value); else storage_.Init(std::forward(value)); } void FreeIfNeeded() { if (!storage_.is_populated_) return; storage_.value_.~T(); storage_.is_populated_ = false; } // For implementing conversion, allow access to other typed OptionalBase // class. template friend class OptionalBase; OptionalStorage storage_; }; // The following {Copy,Move}{Constructible,Assignable} structs are helpers to // implement constructor/assign-operator overloading. Specifically, if T is // is not movable but copyable, Optional's move constructor should not // participate in overload resolution. This inheritance trick implements that. template struct CopyConstructible {}; template <> struct CopyConstructible { constexpr CopyConstructible() = default; constexpr CopyConstructible(const CopyConstructible&) = delete; constexpr CopyConstructible(CopyConstructible&&) = default; CopyConstructible& operator=(const CopyConstructible&) = default; CopyConstructible& operator=(CopyConstructible&&) = default; }; template struct MoveConstructible {}; template <> struct MoveConstructible { constexpr MoveConstructible() = default; constexpr MoveConstructible(const MoveConstructible&) = default; constexpr MoveConstructible(MoveConstructible&&) = delete; MoveConstructible& operator=(const MoveConstructible&) = default; MoveConstructible& operator=(MoveConstructible&&) = default; }; template struct CopyAssignable {}; template <> struct CopyAssignable { constexpr CopyAssignable() = default; constexpr CopyAssignable(const CopyAssignable&) = default; constexpr CopyAssignable(CopyAssignable&&) = default; CopyAssignable& operator=(const CopyAssignable&) = delete; CopyAssignable& operator=(CopyAssignable&&) = default; }; template struct MoveAssignable {}; template <> struct MoveAssignable { constexpr MoveAssignable() = default; constexpr MoveAssignable(const MoveAssignable&) = default; constexpr MoveAssignable(MoveAssignable&&) = default; MoveAssignable& operator=(const MoveAssignable&) = default; MoveAssignable& operator=(MoveAssignable&&) = delete; }; // Helper to conditionally enable converting constructors and assign operators. template struct IsConvertibleFromOptional : std::integral_constant< bool, std::is_constructible&>::value || std::is_constructible&>::value || std::is_constructible&&>::value || std::is_constructible&&>::value || std::is_convertible&, T>::value || std::is_convertible&, T>::value || std::is_convertible&&, T>::value || std::is_convertible&&, T>::value> {}; template struct IsAssignableFromOptional : std::integral_constant< bool, IsConvertibleFromOptional::value || std::is_assignable&>::value || std::is_assignable&>::value || std::is_assignable&&>::value || std::is_assignable&&>::value> {}; // Forward compatibility for C++17. // Introduce one more deeper nested namespace to avoid leaking using std::swap. namespace swappable_impl { using std::swap; struct IsSwappableImpl { // Tests if swap can be called. Check(0) returns true_type iff swap is // available for T. Otherwise, Check's overload resolution falls back to // Check(...) declared below thanks to SFINAE, so returns false_type. template static auto Check(int) -> decltype(swap(std::declval(), std::declval()), std::true_type()); template static std::false_type Check(...); }; } // namespace swappable_impl template struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check(0)) {}; // Forward compatibility for C++20. template using RemoveCvRefT = typename std::remove_cv::type>::type; } // namespace internal // On Windows, by default, empty-base class optimization does not work, // which means even if the base class is empty struct, it still consumes one // byte for its body. __declspec(empty_bases) enables the optimization. // cf) // https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/ #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \ !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC) #define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases) #else #define OPTIONAL_DECLSPEC_EMPTY_BASES #endif // base::Optional is a Chromium version of the C++17 optional class: // std::optional documentation: // http://en.cppreference.com/w/cpp/utility/optional // Chromium documentation: // https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md // // These are the differences between the specification and the implementation: // - Constructors do not use 'constexpr' as it is a C++14 extension. // - 'constexpr' might be missing in some places for reasons specified locally. // - No exceptions are thrown, because they are banned from Chromium. // Marked noexcept for only move constructor and move assign operators. // - All the non-members are in the 'base' namespace instead of 'std'. // // Note that T cannot have a constructor T(Optional) etc. Optional // PERFETTO_CHECKs T's constructor (specifically via IsConvertibleFromOptional), // and in the PERFETTO_CHECK whether T can be constructible from Optional, // which is recursive so it does not work. As of Feb 2018, std::optional C++17 // implementation in both clang and gcc has same limitation. MSVC SFINAE looks // to have different behavior, but anyway it reports an error, too. // // This file is a modified version of optional.h from Chromium at revision // 5e71bd454e60511c1293c0c686544aaa76094424. The changes remove C++14/C++17 // specific code and replace with C++11 counterparts. template class OPTIONAL_DECLSPEC_EMPTY_BASES Optional : public internal::OptionalBase, public internal::CopyConstructible::value>, public internal::MoveConstructible::value>, public internal::CopyAssignable::value && std::is_copy_assignable::value>, public internal::MoveAssignable::value && std::is_move_assignable::value> { public: #undef OPTIONAL_DECLSPEC_EMPTY_BASES using value_type = T; // Defer default/copy/move constructor implementation to OptionalBase. constexpr Optional() = default; constexpr Optional(const Optional& other) = default; constexpr Optional(Optional&& other) noexcept( std::is_nothrow_move_constructible::value) = default; constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit) // Converting copy constructor. "explicit" only if // std::is_convertible::value is false. It is implemented by // declaring two almost same constructors, but that condition in enable_if_t // is different, so that either one is chosen, thanks to SFINAE. template ::value && !internal::IsConvertibleFromOptional::value && std::is_convertible::value, bool>::type = false> Optional(const Optional& other) : internal::OptionalBase(other) {} template ::value && !internal::IsConvertibleFromOptional::value && !std::is_convertible::value, bool>::type = false> explicit Optional(const Optional& other) : internal::OptionalBase(other) {} // Converting move constructor. Similar to converting copy constructor, // declaring two (explicit and non-explicit) constructors. template ::value && !internal::IsConvertibleFromOptional::value && std::is_convertible::value, bool>::type = false> Optional(Optional&& other) : internal::OptionalBase(std::move(other)) {} template ::value && !internal::IsConvertibleFromOptional::value && !std::is_convertible::value, bool>::type = false> explicit Optional(Optional&& other) : internal::OptionalBase(std::move(other)) {} template constexpr explicit Optional(in_place_t, Args&&... args) : internal::OptionalBase(in_place, std::forward(args)...) {} template &, Args...>::value>::type> constexpr explicit Optional(in_place_t, std::initializer_list il, Args&&... args) : internal::OptionalBase(in_place, il, std::forward(args)...) {} // Forward value constructor. Similar to converting constructors, // conditionally explicit. template < typename U = value_type, typename std::enable_if< std::is_constructible::value && !std::is_same, in_place_t>::value && !std::is_same, Optional>::value && std::is_convertible::value, bool>::type = false> constexpr Optional(U&& value) : internal::OptionalBase(in_place, std::forward(value)) {} template < typename U = value_type, typename std::enable_if< std::is_constructible::value && !std::is_same, in_place_t>::value && !std::is_same, Optional>::value && !std::is_convertible::value, bool>::type = false> constexpr explicit Optional(U&& value) : internal::OptionalBase(in_place, std::forward(value)) {} ~Optional() = default; // Defer copy-/move- assign operator implementation to OptionalBase. Optional& operator=(const Optional& other) = default; Optional& operator=(Optional&& other) noexcept( std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) = default; Optional& operator=(nullopt_t) { FreeIfNeeded(); return *this; } // Perfect-forwarded assignment. template typename std::enable_if< !std::is_same, Optional>::value && std::is_constructible::value && std::is_assignable::value && (!std::is_scalar::value || !std::is_same::type, T>::value), Optional&>::type operator=(U&& value) { InitOrAssign(std::forward(value)); return *this; } // Copy assign the state of other. template typename std::enable_if::value && std::is_constructible::value && std::is_assignable::value, Optional&>::type operator=(const Optional& other) { CopyAssign(other); return *this; } // Move assign the state of other. template typename std::enable_if::value && std::is_constructible::value && std::is_assignable::value, Optional&>::type operator=(Optional&& other) { MoveAssign(std::move(other)); return *this; } const T* operator->() const { PERFETTO_DCHECK(storage_.is_populated_); return &storage_.value_; } T* operator->() { PERFETTO_DCHECK(storage_.is_populated_); return &storage_.value_; } const T& operator*() const& { PERFETTO_DCHECK(storage_.is_populated_); return storage_.value_; } T& operator*() & { PERFETTO_DCHECK(storage_.is_populated_); return storage_.value_; } const T&& operator*() const&& { PERFETTO_DCHECK(storage_.is_populated_); return std::move(storage_.value_); } T&& operator*() && { PERFETTO_DCHECK(storage_.is_populated_); return std::move(storage_.value_); } constexpr explicit operator bool() const { return storage_.is_populated_; } constexpr bool has_value() const { return storage_.is_populated_; } T& value() & { PERFETTO_CHECK(storage_.is_populated_); return storage_.value_; } const T& value() const& { PERFETTO_CHECK(storage_.is_populated_); return storage_.value_; } T&& value() && { PERFETTO_CHECK(storage_.is_populated_); return std::move(storage_.value_); } const T&& value() const&& { PERFETTO_CHECK(storage_.is_populated_); return std::move(storage_.value_); } template constexpr T value_or(U&& default_value) const& { static_assert(std::is_convertible::value, "U must be convertible to T"); return storage_.is_populated_ ? storage_.value_ : static_cast(std::forward(default_value)); } template T value_or(U&& default_value) && { static_assert(std::is_convertible::value, "U must be convertible to T"); return storage_.is_populated_ ? std::move(storage_.value_) : static_cast(std::forward(default_value)); } void swap(Optional& other) { if (!storage_.is_populated_ && !other.storage_.is_populated_) return; if (storage_.is_populated_ != other.storage_.is_populated_) { if (storage_.is_populated_) { other.storage_.Init(std::move(storage_.value_)); FreeIfNeeded(); } else { storage_.Init(std::move(other.storage_.value_)); other.FreeIfNeeded(); } return; } PERFETTO_DCHECK(storage_.is_populated_ && other.storage_.is_populated_); using std::swap; swap(**this, *other); } void reset() { FreeIfNeeded(); } template T& emplace(Args&&... args) { FreeIfNeeded(); storage_.Init(std::forward(args)...); return storage_.value_; } template typename std::enable_if< std::is_constructible&, Args&&...>::value, T&>::type emplace(std::initializer_list il, Args&&... args) { FreeIfNeeded(); storage_.Init(il, std::forward(args)...); return storage_.value_; } private: // Accessing template base class's protected member needs explicit // declaration to do so. using internal::OptionalBase::CopyAssign; using internal::OptionalBase::FreeIfNeeded; using internal::OptionalBase::InitOrAssign; using internal::OptionalBase::MoveAssign; using internal::OptionalBase::storage_; }; // Here after defines comparation operators. The definition follows // http://en.cppreference.com/w/cpp/utility/optional/operator_cmp // while bool() casting is replaced by has_value() to meet the chromium // style guide. template bool operator==(const Optional& lhs, const Optional& rhs) { if (lhs.has_value() != rhs.has_value()) return false; if (!lhs.has_value()) return true; return *lhs == *rhs; } template bool operator!=(const Optional& lhs, const Optional& rhs) { if (lhs.has_value() != rhs.has_value()) return true; if (!lhs.has_value()) return false; return *lhs != *rhs; } template bool operator<(const Optional& lhs, const Optional& rhs) { if (!rhs.has_value()) return false; if (!lhs.has_value()) return true; return *lhs < *rhs; } template bool operator<=(const Optional& lhs, const Optional& rhs) { if (!lhs.has_value()) return true; if (!rhs.has_value()) return false; return *lhs <= *rhs; } template bool operator>(const Optional& lhs, const Optional& rhs) { if (!lhs.has_value()) return false; if (!rhs.has_value()) return true; return *lhs > *rhs; } template bool operator>=(const Optional& lhs, const Optional& rhs) { if (!rhs.has_value()) return true; if (!lhs.has_value()) return false; return *lhs >= *rhs; } template constexpr bool operator==(const Optional& opt, nullopt_t) { return !opt; } template constexpr bool operator==(nullopt_t, const Optional& opt) { return !opt; } template constexpr bool operator!=(const Optional& opt, nullopt_t) { return opt.has_value(); } template constexpr bool operator!=(nullopt_t, const Optional& opt) { return opt.has_value(); } template constexpr bool operator<(const Optional&, nullopt_t) { return false; } template constexpr bool operator<(nullopt_t, const Optional& opt) { return opt.has_value(); } template constexpr bool operator<=(const Optional& opt, nullopt_t) { return !opt; } template constexpr bool operator<=(nullopt_t, const Optional&) { return true; } template constexpr bool operator>(const Optional& opt, nullopt_t) { return opt.has_value(); } template constexpr bool operator>(nullopt_t, const Optional&) { return false; } template constexpr bool operator>=(const Optional&, nullopt_t) { return true; } template constexpr bool operator>=(nullopt_t, const Optional& opt) { return !opt; } template constexpr bool operator==(const Optional& opt, const U& value) { return opt.has_value() ? *opt == value : false; } template constexpr bool operator==(const U& value, const Optional& opt) { return opt.has_value() ? value == *opt : false; } template constexpr bool operator!=(const Optional& opt, const U& value) { return opt.has_value() ? *opt != value : true; } template constexpr bool operator!=(const U& value, const Optional& opt) { return opt.has_value() ? value != *opt : true; } template constexpr bool operator<(const Optional& opt, const U& value) { return opt.has_value() ? *opt < value : true; } template constexpr bool operator<(const U& value, const Optional& opt) { return opt.has_value() ? value < *opt : false; } template constexpr bool operator<=(const Optional& opt, const U& value) { return opt.has_value() ? *opt <= value : true; } template constexpr bool operator<=(const U& value, const Optional& opt) { return opt.has_value() ? value <= *opt : false; } template constexpr bool operator>(const Optional& opt, const U& value) { return opt.has_value() ? *opt > value : false; } template constexpr bool operator>(const U& value, const Optional& opt) { return opt.has_value() ? value > *opt : true; } template constexpr bool operator>=(const Optional& opt, const U& value) { return opt.has_value() ? *opt >= value : false; } template constexpr bool operator>=(const U& value, const Optional& opt) { return opt.has_value() ? value >= *opt : true; } template constexpr Optional::type> make_optional(T&& value) { return Optional::type>(std::forward(value)); } template constexpr Optional make_optional(Args&&... args) { return Optional(in_place, std::forward(args)...); } template constexpr Optional make_optional(std::initializer_list il, Args&&... args) { return Optional(in_place, il, std::forward(args)...); } // Partial specialization for a function template is not allowed. Also, it is // not allowed to add overload function to std namespace, while it is allowed // to specialize the template in std. Thus, swap() (kind of) overloading is // defined in base namespace, instead. template typename std::enable_if::value && internal::IsSwappable::value>::type swap(Optional& lhs, Optional& rhs) { lhs.swap(rhs); } } // namespace base } // namespace perfetto template struct std::hash> { size_t operator()(const perfetto::base::Optional& opt) const { return opt == perfetto::base::nullopt ? 0 : std::hash()(*opt); } }; #endif // INCLUDE_PERFETTO_EXT_BASE_OPTIONAL_H_ // gen_amalgamated begin header: include/perfetto/ext/base/string_view.h // gen_amalgamated begin header: include/perfetto/ext/base/hash.h /* * Copyright (C) 2019 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_HASH_H_ #define INCLUDE_PERFETTO_EXT_BASE_HASH_H_ #include #include #include #include #include namespace perfetto { namespace base { // A helper class which computes a 64-bit hash of the input data. // The algorithm used is FNV-1a as it is fast and easy to implement and has // relatively few collisions. // WARNING: This hash function should not be used for any cryptographic purpose. class Hasher { public: // Creates an empty hash object Hasher() {} // Hashes a numeric value. template < typename T, typename std::enable_if::value, bool>::type = true> void Update(T data) { Update(reinterpret_cast(&data), sizeof(data)); } // Using the loop instead of "Update(str, strlen(str))" to avoid looping twice void Update(const char* str) { for (const auto* p = str; *p; ++p) Update(*p); } // Hashes a byte array. void Update(const char* data, size_t size) { for (size_t i = 0; i < size; i++) { result_ ^= static_cast(data[i]); // Note: Arithmetic overflow of unsigned integers is well defined in C++ // standard unlike signed integers. // https://stackoverflow.com/a/41280273 result_ *= kFnv1a64Prime; } } // Allow hashing anything that has a |data| field, a |size| field, // and has the kHashable trait (e.g., base::StringView). template > void Update(const T& t) { Update(t.data(), t.size()); } void Update(const std::string& s) { Update(s.data(), s.size()); } uint64_t digest() const { return result_; } // Usage: // uint64_t hashed_value = Hash::Combine(33, false, "ABC", 458L, 3u, 'x'); template static uint64_t Combine(Ts&&... args) { Hasher hasher; hasher.UpdateAll(std::forward(args)...); return hasher.digest(); } // `hasher.UpdateAll(33, false, "ABC")` is shorthand for: // `hasher.Update(33); hasher.Update(false); hasher.Update("ABC");` void UpdateAll() {} template void UpdateAll(T&& arg, Ts&&... args) { Update(arg); UpdateAll(std::forward(args)...); } private: static constexpr uint64_t kFnv1a64OffsetBasis = 0xcbf29ce484222325; static constexpr uint64_t kFnv1a64Prime = 0x100000001b3; uint64_t result_ = kFnv1a64OffsetBasis; }; // This is for using already-hashed key into std::unordered_map and avoid the // cost of re-hashing. Example: // unordered_map my_map. template struct AlreadyHashed { size_t operator()(const T& x) const { return static_cast(x); } }; // base::Hash uses base::Hasher for integer values and falls base to std::hash // for other types. This is needed as std::hash for integers is just the // identity function and Perfetto uses open-addressing hash table, which are // very sensitive to hash quality and are known to degrade in performance // when using std::hash. template struct Hash { // Version for ints, using base::Hasher. template auto operator()(const U& x) -> typename std::enable_if::value, size_t>::type const { Hasher hash; hash.Update(x); return static_cast(hash.digest()); } // Version for non-ints, falling back to std::hash. template auto operator()(const U& x) -> typename std::enable_if::value, size_t>::type const { return std::hash()(x); } }; } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_HASH_H_ /* * 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ #define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ #include #include #include // gen_amalgamated expanded: #include "perfetto/base/build_config.h" // gen_amalgamated expanded: #include "perfetto/base/logging.h" // gen_amalgamated expanded: #include "perfetto/ext/base/hash.h" namespace perfetto { namespace base { // A string-like object that refers to a non-owned piece of memory. // Strings are internally NOT null terminated. class StringView { public: // Allow hashing with base::Hash. static constexpr bool kHashable = true; static constexpr size_t npos = static_cast(-1); StringView() : data_(nullptr), size_(0) {} StringView(const StringView&) = default; StringView& operator=(const StringView&) = default; StringView(const char* data, size_t size) : data_(data), size_(size) { PERFETTO_DCHECK(size == 0 || data != nullptr); } // Allow implicit conversion from any class that has a |data| and |size| field // and has the kConvertibleToStringView trait (e.g., protozero::ConstChars). template > StringView(const T& x) : StringView(x.data, x.size) { PERFETTO_DCHECK(x.size == 0 || x.data != nullptr); } // Creates a StringView from a null-terminated C string. // Deliberately not "explicit". StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) { PERFETTO_DCHECK(cstr != nullptr); } // This instead has to be explicit, as creating a StringView out of a // std::string can be subtle. explicit StringView(const std::string& str) : data_(str.data()), size_(str.size()) {} bool empty() const { return size_ == 0; } size_t size() const { return size_; } const char* data() const { return data_; } const char* begin() const { return data_; } const char* end() const { return data_ + size_; } char at(size_t pos) const { PERFETTO_DCHECK(pos < size_); return data_[pos]; } size_t find(char c, size_t start_pos = 0) const { for (size_t i = start_pos; i < size_; ++i) { if (data_[i] == c) return i; } return npos; } size_t find(const StringView& str, size_t start_pos = 0) const { if (start_pos > size()) return npos; auto it = std::search(begin() + start_pos, end(), str.begin(), str.end()); size_t pos = static_cast(it - begin()); return pos + str.size() <= size() ? pos : npos; } size_t find(const char* str, size_t start_pos = 0) const { return find(StringView(str), start_pos); } size_t rfind(char c) const { for (size_t i = size_; i > 0; --i) { if (data_[i - 1] == c) return i - 1; } return npos; } StringView substr(size_t pos, size_t count = npos) const { if (pos >= size_) return StringView("", 0); size_t rcount = std::min(count, size_ - pos); return StringView(data_ + pos, rcount); } bool CaseInsensitiveEq(const StringView& other) const { if (size() != other.size()) return false; if (size() == 0) return true; #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) return _strnicmp(data(), other.data(), size()) == 0; #else return strncasecmp(data(), other.data(), size()) == 0; #endif } bool StartsWith(const StringView& other) const { if (other.size() == 0) return true; if (size() == 0) return false; if (other.size() > size()) return false; for (uint32_t i = 0; i < other.size(); ++i) { if (at(i) != other.at(i)) return false; } return true; } bool EndsWith(const StringView& other) const { if (other.size() == 0) return true; if (size() == 0) return false; if (other.size() > size()) return false; const size_t off = size() - other.size(); for (size_t i = 0; i < other.size(); ++i) { if (at(off + i) != other.at(i)) return false; } return true; } std::string ToStdString() const { return size_ == 0 ? "" : std::string(data_, size_); } uint64_t Hash() const { base::Hasher hasher; hasher.Update(data_, size_); return hasher.digest(); } private: const char* data_ = nullptr; size_t size_ = 0; }; inline bool operator==(const StringView& x, const StringView& y) { if (x.size() != y.size()) return false; if (x.size() == 0) return true; return memcmp(x.data(), y.data(), x.size()) == 0; } inline bool operator!=(const StringView& x, const StringView& y) { return !(x == y); } inline bool operator<(const StringView& x, const StringView& y) { auto size = std::min(x.size(), y.size()); if (size == 0) return x.size() < y.size(); int result = memcmp(x.data(), y.data(), size); return result < 0 || (result == 0 && x.size() < y.size()); } inline bool operator>=(const StringView& x, const StringView& y) { return !(x < y); } inline bool operator>(const StringView& x, const StringView& y) { return y < x; } inline bool operator<=(const StringView& x, const StringView& y) { return !(y < x); } } // namespace base } // namespace perfetto template <> struct std::hash<::perfetto::base::StringView> { size_t operator()(const ::perfetto::base::StringView& sv) const { return static_cast(sv.Hash()); } }; #endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ // gen_amalgamated begin header: include/perfetto/ext/base/utils.h // gen_amalgamated begin header: include/perfetto/ext/base/sys_types.h /* * Copyright (C) 2022 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ #define INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ // This headers deals with sys types commonly used in the codebase that are // missing on Windows. #include // gen_amalgamated expanded: #include "perfetto/base/build_config.h" #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC) // MinGW has these. clang-cl and MSVC, which use just the Windows SDK, don't. using uid_t = unsigned int; using pid_t = int; #endif // !GCC #if defined(_WIN64) using ssize_t = int64_t; #else using ssize_t = long; #endif // _WIN64 #endif // OS_WIN namespace perfetto { namespace base { constexpr uid_t kInvalidUid = static_cast(-1); constexpr pid_t kInvalidPid = static_cast(-1); } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ /* * Copyright (C) 2017 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ #define INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ #include #include #include #include #include #include #include #include // gen_amalgamated expanded: #include "perfetto/base/build_config.h" // gen_amalgamated expanded: #include "perfetto/base/compiler.h" // gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h" #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // Even if Windows has errno.h, the all syscall-restart behavior does not apply. // Trying to handle EINTR can cause more harm than good if errno is left stale. // Chromium does the same. #define PERFETTO_EINTR(x) (x) #else #define PERFETTO_EINTR(x) \ ([&] { \ decltype(x) eintr_wrapper_result; \ do { \ eintr_wrapper_result = (x); \ } while (eintr_wrapper_result == -1 && errno == EINTR); \ return eintr_wrapper_result; \ }()) #endif namespace perfetto { namespace base { // Do not add new usages of kPageSize, consider using GetSysPageSize() below. // TODO(primiano): over time the semantic of kPageSize became too ambiguous. // Strictly speaking, this constant is incorrect on some new devices where the // page size can be 16K (e.g., crbug.com/1116576). Unfortunately too much code // ended up depending on kPageSize for purposes that are not strictly related // with the kernel's mm subsystem. constexpr size_t kPageSize = 4096; // Returns the system's page size. Use this when dealing with mmap, madvise and // similar mm-related syscalls. uint32_t GetSysPageSize(); template constexpr size_t ArraySize(const T (&)[TSize]) { return TSize; } // Function object which invokes 'free' on its parameter, which must be // a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr: // // std::unique_ptr foo_ptr( // static_cast(malloc(sizeof(int)))); struct FreeDeleter { inline void operator()(void* ptr) const { free(ptr); } }; template constexpr T AssumeLittleEndian(T value) { #if !PERFETTO_IS_LITTLE_ENDIAN() static_assert(false, "Unimplemented on big-endian archs"); #endif return value; } // Round up |size| to a multiple of |alignment| (must be a power of two). template constexpr size_t AlignUp(size_t size) { static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2"); return (size + alignment - 1) & ~(alignment - 1); } inline bool IsAgain(int err) { return err == EAGAIN || err == EWOULDBLOCK; } // setenv(2)-equivalent. Deals with Windows vs Posix discrepancies. void SetEnv(const std::string& key, const std::string& value); // unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies. void UnsetEnv(const std::string& key); // Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms. // This forces the allocator to release freed memory. This is used to work // around various Scudo inefficiencies. See b/170217718. void MaybeReleaseAllocatorMemToOS(); // geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc). uid_t GetCurrentUserId(); // Forks the process. // Parent: prints the PID of the child, calls |parent_cb| and exits from the // process with its return value. // Child: redirects stdio onto /dev/null, chdirs into / and returns. void Daemonize(std::function parent_cb); // Returns the path of the current executable, e.g. /foo/bar/exe. std::string GetCurExecutablePath(); // Returns the directory where the current executable lives in, e.g. /foo/bar. // This is independent of cwd(). std::string GetCurExecutableDir(); // Memory returned by AlignedAlloc() must be freed via AlignedFree() not just // free. It makes a difference on Windows where _aligned_malloc() and // _aligned_free() must be paired. // Prefer using the AlignedAllocTyped() below which takes care of the pairing. void* AlignedAlloc(size_t alignment, size_t size); void AlignedFree(void*); // A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}. template struct AlignedDeleter { inline void operator()(T* ptr) const { AlignedFree(ptr); } }; // The remove_extent here and below is to allow defining unique_ptr. // As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes // always a T*, not a T[]*. template using AlignedUniquePtr = std::unique_ptr::type>>; template AlignedUniquePtr AlignedAllocTyped(size_t n_membs) { using TU = typename std::remove_extent::type; return AlignedUniquePtr( static_cast(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs))); } // A RAII wrapper to invoke a function when leaving a function/scope. template class OnScopeExitWrapper { public: explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {} OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept : f_(std::move(other.f_)), active_(other.active_) { other.active_ = false; } ~OnScopeExitWrapper() { if (active_) f_(); } private: Func f_; bool active_; }; template PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper OnScopeExit(Func f) { return OnScopeExitWrapper(std::move(f)); } // Returns a xxd-style hex dump (hex + ascii chars) of the input data. std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16); inline std::string HexDump(const std::string& data, size_t bytes_per_line = 16) { return HexDump(data.data(), data.size(), bytes_per_line); } } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ /* * Copyright (C) 2021 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ #define INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ #include // gen_amalgamated expanded: #include "perfetto/ext/base/optional.h" // gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" // gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" // For ssize_t. namespace perfetto { namespace base { // Returns the length of the destination string (included '=' padding). // Does NOT include the size of the string null terminator. inline size_t Base64EncSize(size_t src_size) { return (src_size + 2) / 3 * 4; } // Returns the upper bound on the length of the destination buffer. // The actual decoded length might be <= the number returned here. inline size_t Base64DecSize(size_t src_size) { return (src_size + 3) / 4 * 3; } // Does NOT null-terminate |dst|. ssize_t Base64Encode(const void* src, size_t src_size, char* dst, size_t dst_size); std::string Base64Encode(const void* src, size_t src_size); inline std::string Base64Encode(StringView sv) { return Base64Encode(sv.data(), sv.size()); } // Returns -1 in case of failure. ssize_t Base64Decode(const char* src, size_t src_size, uint8_t* dst, size_t dst_size); Optional Base64Decode(const char* src, size_t src_size); inline Optional Base64Decode(StringView sv) { return Base64Decode(sv.data(), sv.size()); } } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ /* * Copyright (C) 2021 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. */ // gen_amalgamated expanded: #include "perfetto/ext/base/base64.h" namespace perfetto { namespace base { namespace { constexpr char kPadding = '='; constexpr char kEncTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static_assert(sizeof(kEncTable) == (1u << 6) + sizeof('\0'), "Bad table size"); // Maps an ASCII character to its 6-bit value. It only contains translations // from '+' to 'z'. Supports the standard (+/) and URL-safe (-_) alphabets. constexpr uint8_t kX = 0xff; // Value used for invalid characters constexpr uint8_t kDecTable[] = { 62, kX, 62, kX, 63, 52, 53, 54, 55, 56, // 00 - 09 57, 58, 59, 60, 61, kX, kX, kX, 0, kX, // 10 - 19 kX, kX, 0, 1, 2, 3, 4, 5, 6, 7, // 20 - 29 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, // 30 - 39 18, 19, 20, 21, 22, 23, 24, 25, kX, kX, // 40 - 49 kX, kX, 63, kX, 26, 27, 28, 29, 30, 31, // 50 - 59 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, // 60 - 69 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 70 - 79 }; constexpr char kMinDecChar = '+'; constexpr char kMaxDecChar = 'z'; static_assert(kMaxDecChar - kMinDecChar <= sizeof(kDecTable), "Bad table size"); inline uint8_t DecodeChar(char c) { if (c < kMinDecChar || c > kMaxDecChar) return kX; return kDecTable[c - kMinDecChar]; } } // namespace ssize_t Base64Encode(const void* src, size_t src_size, char* dst, size_t dst_size) { const size_t padded_dst_size = Base64EncSize(src_size); if (dst_size < padded_dst_size) return -1; // Not enough space in output. const uint8_t* rd = static_cast(src); const uint8_t* const end = rd + src_size; size_t wr_size = 0; while (rd < end) { uint8_t s[3]{}; s[0] = *(rd++); dst[wr_size++] = kEncTable[s[0] >> 2]; uint8_t carry0 = static_cast((s[0] & 0x03) << 4); if (PERFETTO_LIKELY(rd < end)) { s[1] = *(rd++); dst[wr_size++] = kEncTable[carry0 | (s[1] >> 4)]; } else { dst[wr_size++] = kEncTable[carry0]; dst[wr_size++] = kPadding; dst[wr_size++] = kPadding; break; } uint8_t carry1 = static_cast((s[1] & 0x0f) << 2); if (PERFETTO_LIKELY(rd < end)) { s[2] = *(rd++); dst[wr_size++] = kEncTable[carry1 | (s[2] >> 6)]; } else { dst[wr_size++] = kEncTable[carry1]; dst[wr_size++] = kPadding; break; } dst[wr_size++] = kEncTable[s[2] & 0x3f]; } PERFETTO_DCHECK(wr_size == padded_dst_size); return static_cast(padded_dst_size); } std::string Base64Encode(const void* src, size_t src_size) { std::string dst; dst.resize(Base64EncSize(src_size)); auto res = Base64Encode(src, src_size, &dst[0], dst.size()); PERFETTO_CHECK(res == static_cast(dst.size())); return dst; } ssize_t Base64Decode(const char* src, size_t src_size, uint8_t* dst, size_t dst_size) { const size_t min_dst_size = Base64DecSize(src_size); if (dst_size < min_dst_size) return -1; const char* rd = src; const char* const end = src + src_size; size_t wr_size = 0; char s[4]{}; while (rd < end) { uint8_t d[4]; for (uint32_t j = 0; j < 4; j++) { // Padding is only feasible for the last 2 chars of each group of 4. s[j] = rd < end ? *(rd++) : (j < 2 ? '\0' : kPadding); d[j] = DecodeChar(s[j]); if (d[j] == kX) return -1; // Invalid input char. } dst[wr_size] = static_cast((d[0] << 2) | (d[1] >> 4)); dst[wr_size + 1] = static_cast((d[1] << 4) | (d[2] >> 2)); dst[wr_size + 2] = static_cast((d[2] << 6) | (d[3])); wr_size += 3; } PERFETTO_CHECK(wr_size <= dst_size); wr_size -= (s[3] == kPadding ? 1 : 0) + (s[2] == kPadding ? 1 : 0); return static_cast(wr_size); } Optional Base64Decode(const char* src, size_t src_size) { std::string dst; dst.resize(Base64DecSize(src_size)); auto res = Base64Decode(src, src_size, reinterpret_cast(&dst[0]), dst.size()); if (res < 0) return nullopt; // Decoding error. PERFETTO_CHECK(res <= static_cast(dst.size())); dst.resize(static_cast(res)); return base::make_optional(dst); } } // namespace base } // namespace perfetto // gen_amalgamated begin source: src/base/crash_keys.cc // gen_amalgamated begin header: include/perfetto/ext/base/crash_keys.h /* * Copyright (C) 2021 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ #define INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ #include #include #include #include // gen_amalgamated expanded: #include "perfetto/base/compiler.h" // gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" // Crash keys are very simple global variables with static-storage that // are reported on crash time for managed crashes (CHECK/FATAL/Watchdog). // - Translation units can define a CrashKey and register it at some point // during initialization. // - CrashKey instances must be long-lived. They should really be just global // static variable in the anonymous namespace. // Example: // subsystem_1.cc // CrashKey g_client_id("ipc_client_id"); // ... // OnIpcReceived(client_id) { // g_client_id.Set(client_id); // ... // Process the IPC // g_client_id.Clear(); // } // Or equivalently: // OnIpcReceived(client_id) { // auto scoped_key = g_client_id.SetScoped(client_id); // ... // Process the IPC // } // // If a crash happens while processing the IPC, the crash report will // have a line "ipc_client_id: 42". // // Thread safety considerations: // CrashKeys can be registered and set/cleared from any thread. // There is no compelling use-case to have full acquire/release consistency when // setting a key. This means that if a thread crashes immediately after a // crash key has been set on another thread, the value printed on the crash // report could be incomplete. The code guarantees defined behavior and does // not rely on null-terminated string (in the worst case 32 bytes of random // garbage will be printed out). // The tests live in logging_unittest.cc. namespace perfetto { namespace base { constexpr size_t kCrashKeyMaxStrSize = 32; // CrashKey instances must be long lived class CrashKey { public: class ScopedClear { public: explicit ScopedClear(CrashKey* k) : key_(k) {} ~ScopedClear() { if (key_) key_->Clear(); } ScopedClear(const ScopedClear&) = delete; ScopedClear& operator=(const ScopedClear&) = delete; ScopedClear& operator=(ScopedClear&&) = delete; ScopedClear(ScopedClear&& other) noexcept : key_(other.key_) { other.key_ = nullptr; } private: CrashKey* key_; }; // constexpr so it can be used in the anon namespace without requiring a // global constructor. // |name| must be a long-lived string. constexpr explicit CrashKey(const char* name) : registered_{}, type_(Type::kUnset), name_(name), str_value_{} {} CrashKey(const CrashKey&) = delete; CrashKey& operator=(const CrashKey&) = delete; CrashKey(CrashKey&&) = delete; CrashKey& operator=(CrashKey&&) = delete; enum class Type : uint8_t { kUnset = 0, kInt, kStr }; void Clear() { int_value_.store(0, std::memory_order_relaxed); type_.store(Type::kUnset, std::memory_order_relaxed); } void Set(int64_t value) { int_value_.store(value, std::memory_order_relaxed); type_.store(Type::kInt, std::memory_order_relaxed); if (PERFETTO_UNLIKELY(!registered_.load(std::memory_order_relaxed))) Register(); } void Set(StringView sv) { size_t len = std::min(sv.size(), sizeof(str_value_) - 1); for (size_t i = 0; i < len; ++i) str_value_[i].store(sv.data()[i], std::memory_order_relaxed); str_value_[len].store('\0', std::memory_order_relaxed); type_.store(Type::kStr, std::memory_order_relaxed); if (PERFETTO_UNLIKELY(!registered_.load(std::memory_order_relaxed))) Register(); } ScopedClear SetScoped(int64_t value) PERFETTO_WARN_UNUSED_RESULT { Set(value); return ScopedClear(this); } ScopedClear SetScoped(StringView sv) PERFETTO_WARN_UNUSED_RESULT { Set(sv); return ScopedClear(this); } void Register(); int64_t int_value() const { return int_value_.load(std::memory_order_relaxed); } size_t ToString(char* dst, size_t len); private: std::atomic registered_; std::atomic type_; const char* const name_; union { std::atomic str_value_[kCrashKeyMaxStrSize]; std::atomic int_value_; }; }; // Fills |dst| with a string containing one line for each crash key // (excluding the unset ones). // Returns number of chars written, without counting the NUL terminator. // This is used in logging.cc when emitting the crash report abort message. size_t SerializeCrashKeys(char* dst, size_t len); void UnregisterAllCrashKeysForTesting(); } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ // gen_amalgamated begin header: include/perfetto/ext/base/string_utils.h /* * 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ #define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ #include #include #include #include #include #include // gen_amalgamated expanded: #include "perfetto/ext/base/optional.h" // gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" namespace perfetto { namespace base { inline char Lowercase(char c) { return ('A' <= c && c <= 'Z') ? static_cast(c - ('A' - 'a')) : c; } inline char Uppercase(char c) { return ('a' <= c && c <= 'z') ? static_cast(c + ('A' - 'a')) : c; } inline Optional CStringToUInt32(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtoul(s, &endptr, base)); return (*s && !*endptr) ? base::make_optional(value) : base::nullopt; } inline Optional CStringToInt32(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtol(s, &endptr, base)); return (*s && !*endptr) ? base::make_optional(value) : base::nullopt; } // Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000... inline Optional CStringToInt64(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtoll(s, &endptr, base)); return (*s && !*endptr) ? base::make_optional(value) : base::nullopt; } inline Optional CStringToUInt64(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtoull(s, &endptr, base)); return (*s && !*endptr) ? base::make_optional(value) : base::nullopt; } double StrToD(const char* nptr, char** endptr); inline Optional CStringToDouble(const char* s) { char* endptr = nullptr; double value = StrToD(s, &endptr); Optional result(base::nullopt); if (*s != '\0' && *endptr == '\0') result = value; return result; } inline Optional StringToUInt32(const std::string& s, int base = 10) { return CStringToUInt32(s.c_str(), base); } inline Optional StringToInt32(const std::string& s, int base = 10) { return CStringToInt32(s.c_str(), base); } inline Optional StringToUInt64(const std::string& s, int base = 10) { return CStringToUInt64(s.c_str(), base); } inline Optional StringToInt64(const std::string& s, int base = 10) { return CStringToInt64(s.c_str(), base); } inline Optional StringToDouble(const std::string& s) { return CStringToDouble(s.c_str()); } bool StartsWith(const std::string& str, const std::string& prefix); bool EndsWith(const std::string& str, const std::string& suffix); bool StartsWithAny(const std::string& str, const std::vector& prefixes); bool Contains(const std::string& haystack, const std::string& needle); bool Contains(const std::string& haystack, char needle); size_t Find(const StringView& needle, const StringView& haystack); bool CaseInsensitiveEqual(const std::string& first, const std::string& second); std::string Join(const std::vector& parts, const std::string& delim); std::vector SplitString(const std::string& text, const std::string& delimiter); std::string StripPrefix(const std::string& str, const std::string& prefix); std::string StripSuffix(const std::string& str, const std::string& suffix); std::string ToLower(const std::string& str); std::string ToUpper(const std::string& str); std::string StripChars(const std::string& str, const std::string& chars, char replacement); std::string ToHex(const char* data, size_t size); inline std::string ToHex(const std::string& s) { return ToHex(s.c_str(), s.size()); } std::string IntToHexString(uint32_t number); std::string Uint64ToHexString(uint64_t number); std::string Uint64ToHexStringNoPrefix(uint64_t number); std::string ReplaceAll(std::string str, const std::string& to_replace, const std::string& replacement); // A BSD-style strlcpy without the return value. // Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0 // terminates |dst|, as long as |dst_size| is not 0. // Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|. // Returns nothing. The BSD strlcpy returns the size of |src|, which might // be > |dst_size|. Anecdotal experience suggests people assume the return value // is the number of bytes written in |dst|. That assumption can lead to // dangerous bugs. // In order to avoid being subtly uncompliant with strlcpy AND avoid misuse, // the choice here is to return nothing. inline void StringCopy(char* dst, const char* src, size_t dst_size) { for (size_t i = 0; i < dst_size; ++i) { if ((dst[i] = src[i]) == '\0') { return; // We hit and copied the null terminator. } } // We were left off at dst_size. We over copied 1 byte. Null terminate. if (PERFETTO_LIKELY(dst_size > 0)) dst[dst_size - 1] = 0; } // Like snprintf() but returns the number of chars *actually* written (without // counting the null terminator) NOT "the number of chars which would have been // written to the final string if enough space had been available". // This should be used in almost all cases when the caller uses the return value // of snprintf(). If the return value is not used, there is no benefit in using // this wrapper, as this just calls snprintf() and mangles the return value. // It always null-terminates |dst| (even in case of errors), unless // |dst_size| == 0. // Examples: // SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0". // SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0". // SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0". // SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0". // SprintfTrunc(x, 1, "123"): returns 0 and writes "\0". // SprintfTrunc(x, 0, "123"): returns 0 and writes nothing. // NOTE: This means that the caller has no way to tell when truncation happens // vs the edge case of *just* fitting in the buffer. size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...) PERFETTO_PRINTF_FORMAT(3, 4); // Line number starts from 1 struct LineWithOffset { base::StringView line; uint32_t line_offset; uint32_t line_num; }; // For given string and offset Pfinds a line with character for // which offset points, what number is this line (starts from 1), and the offset // inside this line. returns nullopt if the offset points to // line break character or exceeds string length. base::Optional FindLineWithOffset(base::StringView str, uint32_t offset); // A helper class to facilitate construction and usage of write-once stack // strings. // Example usage: // StackString<32> x("format %d %s", 42, string_arg); // TakeString(x.c_str() | x.string_view() | x.ToStdString()); // Rather than char x[32] + sprintf. // Advantages: // - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly // by fearing unknown snprintf failure modes). // - Makes the code more robust in case of snprintf truncations (len() and // string_view() will return the truncated length, unlike snprintf). template class StackString { public: explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3) StackString(const char* fmt, ...) { buf_[0] = '\0'; va_list args; va_start(args, fmt); int res = vsnprintf(buf_, sizeof(buf_), fmt, args); va_end(args); buf_[sizeof(buf_) - 1] = '\0'; len_ = res < 0 ? 0 : std::min(static_cast(res), sizeof(buf_) - 1); } StringView string_view() const { return StringView(buf_, len_); } std::string ToStdString() const { return std::string(buf_, len_); } const char* c_str() const { return buf_; } size_t len() const { return len_; } private: char buf_[N]; size_t len_ = 0; // Does not include the \0. }; } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ /* * Copyright (C) 2021 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. */ // gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h" #include #include #include // gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h" namespace perfetto { namespace base { namespace { constexpr size_t kMaxKeys = 32; std::atomic g_keys[kMaxKeys]{}; std::atomic g_num_keys{}; } // namespace void CrashKey::Register() { // If doesn't matter if we fail below. If there are no slots left, don't // keep trying re-registering on every Set(), the outcome won't change. // If two threads raced on the Register(), avoid registering the key twice. if (registered_.exchange(true)) return; uint32_t slot = g_num_keys.fetch_add(1); if (slot >= kMaxKeys) { PERFETTO_LOG("Too many crash keys registered"); return; } g_keys[slot].store(this); } // Returns the number of chars written, without counting the \0. size_t CrashKey::ToString(char* dst, size_t len) { if (len > 0) *dst = '\0'; switch (type_.load(std::memory_order_relaxed)) { case Type::kUnset: break; case Type::kInt: return SprintfTrunc(dst, len, "%s: %" PRId64 "\n", name_, int_value_.load(std::memory_order_relaxed)); case Type::kStr: char buf[sizeof(str_value_)]; for (size_t i = 0; i < sizeof(str_value_); i++) buf[i] = str_value_[i].load(std::memory_order_relaxed); // Don't assume |str_value_| is properly null-terminated. return SprintfTrunc(dst, len, "%s: %.*s\n", name_, int(sizeof(buf)), buf); } return 0; } void UnregisterAllCrashKeysForTesting() { g_num_keys.store(0); for (auto& key : g_keys) key.store(nullptr); } size_t SerializeCrashKeys(char* dst, size_t len) { size_t written = 0; uint32_t num_keys = g_num_keys.load(); if (len > 0) *dst = '\0'; for (uint32_t i = 0; i < num_keys && written < len; i++) { CrashKey* key = g_keys[i].load(); if (!key) continue; // Can happen if we hit this between the add and the store. written += key->ToString(dst + written, len - written); } PERFETTO_DCHECK(written <= len); PERFETTO_DCHECK(len == 0 || dst[written] == '\0'); return written; } } // namespace base } // namespace perfetto // gen_amalgamated begin source: src/base/ctrl_c_handler.cc // gen_amalgamated begin header: include/perfetto/ext/base/ctrl_c_handler.h /* * Copyright (C) 2021 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ #define INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ namespace perfetto { namespace base { // On Linux/Android/Mac: installs SIGINT + SIGTERM signal handlers. // On Windows: installs a SetConsoleCtrlHandler() handler. // The passed handler must be async safe. using CtrlCHandlerFunction = void (*)(); void InstallCtrCHandler(CtrlCHandlerFunction); } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ /* * Copyright (C) 2021 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. */ // gen_amalgamated expanded: #include "perfetto/ext/base/ctrl_c_handler.h" // gen_amalgamated expanded: #include "perfetto/base/build_config.h" // gen_amalgamated expanded: #include "perfetto/base/compiler.h" // gen_amalgamated expanded: #include "perfetto/base/logging.h" #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #include #include #else #include #include #endif namespace perfetto { namespace base { namespace { CtrlCHandlerFunction g_handler = nullptr; } void InstallCtrCHandler(CtrlCHandlerFunction handler) { PERFETTO_CHECK(g_handler == nullptr); g_handler = handler; #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) auto trampoline = [](DWORD type) -> int { if (type == CTRL_C_EVENT) { g_handler(); return true; } return false; }; ::SetConsoleCtrlHandler(trampoline, true); #elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) // Setup signal handler. struct sigaction sa {}; // Glibc headers for sa_sigaction trigger this. #pragma GCC diagnostic push #if defined(__clang__) #pragma GCC diagnostic ignored "-Wdisabled-macro-expansion" #endif sa.sa_handler = [](int) { g_handler(); }; sa.sa_flags = static_cast(SA_RESETHAND | SA_RESTART); #pragma GCC diagnostic pop sigaction(SIGINT, &sa, nullptr); sigaction(SIGTERM, &sa, nullptr); #else // Do nothing on NaCL and Fuchsia. ignore_result(handler); #endif } } // namespace base } // namespace perfetto // gen_amalgamated begin source: src/base/event_fd.cc // gen_amalgamated begin header: include/perfetto/ext/base/event_fd.h // gen_amalgamated begin header: include/perfetto/base/platform_handle.h /* * 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. */ #ifndef INCLUDE_PERFETTO_BASE_PLATFORM_HANDLE_H_ #define INCLUDE_PERFETTO_BASE_PLATFORM_HANDLE_H_ // gen_amalgamated expanded: #include "perfetto/base/build_config.h" namespace perfetto { namespace base { // PlatformHandle should be used only for types that are HANDLE(s) in Windows. // It should NOT be used to blanket-replace "int fd" in the codebase. // Windows has two types of "handles", which, in UNIX-land, both map to int: // 1. File handles returned by the posix-compatibility API like _open(). // These are just int(s) and should stay such, because all the posix-like API // in Windows.h take an int, not a HANDLE. // 2. Handles returned by old-school WINAPI like CreateFile, CreateEvent etc. // These are proper HANDLE(s). PlatformHandle should be used here. #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // Windows.h typedefs HANDLE to void*. We use void* here to avoid leaking // Windows.h through our headers. using PlatformHandle = void*; // On Windows both nullptr and 0xffff... (INVALID_HANDLE_VALUE) are invalid. struct PlatformHandleChecker { static inline bool IsValid(PlatformHandle h) { return h && h != reinterpret_cast(-1); } }; #else using PlatformHandle = int; struct PlatformHandleChecker { static inline bool IsValid(PlatformHandle h) { return h >= 0; } }; #endif // The definition of this lives in base/file_utils.cc (to avoid creating an // extra build edge for a one liner). This is really an alias for close() (UNIX) // CloseHandle() (Windows). THe indirection layer is just to avoid leaking // system headers like Windows.h through perfetto headers. // Thre return value is always UNIX-style: 0 on success, -1 on failure. int ClosePlatformHandle(PlatformHandle); } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_BASE_PLATFORM_HANDLE_H_ // gen_amalgamated begin header: include/perfetto/ext/base/scoped_file.h /* * Copyright (C) 2017 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ #define INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ // gen_amalgamated expanded: #include "perfetto/base/build_config.h" #include #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #include // For DIR* / opendir(). #endif #include // gen_amalgamated expanded: #include "perfetto/base/export.h" // gen_amalgamated expanded: #include "perfetto/base/logging.h" // gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" namespace perfetto { namespace base { namespace internal { // Used for the most common cases of ScopedResource where there is only one // invalid value. template struct DefaultValidityChecker { static bool IsValid(T t) { return t != InvalidValue; } }; } // namespace internal // RAII classes for auto-releasing fds and dirs. // if T is a pointer type, InvalidValue must be nullptr. Doing otherwise // causes weird unexpected behaviors (See https://godbolt.org/z/5nGMW4). template > class ScopedResource { public: using ValidityChecker = Checker; static constexpr T kInvalid = InvalidValue; explicit ScopedResource(T t = InvalidValue) : t_(t) {} ScopedResource(ScopedResource&& other) noexcept { t_ = other.t_; other.t_ = InvalidValue; } ScopedResource& operator=(ScopedResource&& other) { reset(other.t_); other.t_ = InvalidValue; return *this; } T get() const { return t_; } T operator*() const { return t_; } explicit operator bool() const { return Checker::IsValid(t_); } void reset(T r = InvalidValue) { if (Checker::IsValid(t_)) { int res = CloseFunction(t_); if (CheckClose) PERFETTO_CHECK(res == 0); } t_ = r; } T release() { T t = t_; t_ = InvalidValue; return t; } ~ScopedResource() { reset(InvalidValue); } private: ScopedResource(const ScopedResource&) = delete; ScopedResource& operator=(const ScopedResource&) = delete; T t_; }; // Declared in file_utils.h. Forward declared to avoid #include cycles. int PERFETTO_EXPORT_COMPONENT CloseFile(int fd); // Use this for file resources obtained via open() and similar APIs. using ScopedFile = ScopedResource; using ScopedFstream = ScopedResource; // Use this for resources that are HANDLE on Windows. See comments in // platform_handle.h #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) using ScopedPlatformHandle = ScopedResource; #else // On non-windows systems we alias ScopedPlatformHandle to ScopedFile because // they are really the same. This is to allow assignments between the two in // Linux-specific code paths that predate ScopedPlatformHandle. static_assert(std::is_same::value, ""); using ScopedPlatformHandle = ScopedFile; // DIR* does not exist on Windows. using ScopedDir = ScopedResource; #endif } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ /* * 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ #define INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ // gen_amalgamated expanded: #include "perfetto/base/build_config.h" // gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" // gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" namespace perfetto { namespace base { // A waitable event that can be used with poll/select. // This is really a wrapper around eventfd_create with a pipe-based fallback // for other platforms where eventfd is not supported. class EventFd { public: EventFd(); ~EventFd(); EventFd(EventFd&&) noexcept = default; EventFd& operator=(EventFd&&) = default; // The non-blocking file descriptor that can be polled to wait for the event. PlatformHandle fd() const { return event_handle_.get(); } // Can be called from any thread. void Notify(); // Can be called from any thread. If more Notify() are queued a Clear() call // can clear all of them (up to 16 per call). void Clear(); private: // The eventfd, when eventfd is supported, otherwise this is the read end of // the pipe for fallback mode. ScopedPlatformHandle event_handle_; #if !PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) && \ !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \ !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // On Mac and other non-Linux UNIX platforms a pipe-based fallback is used. // The write end of the wakeup pipe. ScopedFile write_fd_; #endif }; } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ // gen_amalgamated begin header: include/perfetto/ext/base/pipe.h /* * 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ #define INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ // gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" // gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" namespace perfetto { namespace base { class Pipe { public: enum Flags { kBothBlock = 0, #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) kBothNonBlock, kRdNonBlock, kWrNonBlock, #endif }; static Pipe Create(Flags = kBothBlock); Pipe(); Pipe(Pipe&&) noexcept; Pipe& operator=(Pipe&&); ScopedPlatformHandle rd; ScopedPlatformHandle wr; }; } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ /* * 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. */ // gen_amalgamated expanded: #include "perfetto/base/build_config.h" #include #include #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #include #include #elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) #include #include #else // Mac, Fuchsia and other non-Linux UNIXes #include #endif // gen_amalgamated expanded: #include "perfetto/base/logging.h" // gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h" // gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h" // gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" namespace perfetto { namespace base { EventFd::~EventFd() = default; #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) EventFd::EventFd() { event_handle_.reset( CreateEventA(/*lpEventAttributes=*/nullptr, /*bManualReset=*/true, /*bInitialState=*/false, /*bInitialState=*/nullptr)); } void EventFd::Notify() { if (!SetEvent(event_handle_.get())) // 0: fail, !0: success, unlike UNIX. PERFETTO_DFATAL("EventFd::Notify()"); } void EventFd::Clear() { if (!ResetEvent(event_handle_.get())) // 0: fail, !0: success, unlike UNIX. PERFETTO_DFATAL("EventFd::Clear()"); } #elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) EventFd::EventFd() { event_handle_.reset(eventfd(/*initval=*/0, EFD_CLOEXEC | EFD_NONBLOCK)); PERFETTO_CHECK(event_handle_); } void EventFd::Notify() { const uint64_t value = 1; ssize_t ret = write(event_handle_.get(), &value, sizeof(value)); if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Notify()"); } void EventFd::Clear() { uint64_t value; ssize_t ret = PERFETTO_EINTR(read(event_handle_.get(), &value, sizeof(value))); if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Clear()"); } #else EventFd::EventFd() { // Make the pipe non-blocking so that we never block the waking thread (either // the main thread or another one) when scheduling a wake-up. Pipe pipe = Pipe::Create(Pipe::kBothNonBlock); event_handle_ = ScopedPlatformHandle(std::move(pipe.rd).release()); write_fd_ = std::move(pipe.wr); } void EventFd::Notify() { const uint64_t value = 1; ssize_t ret = write(write_fd_.get(), &value, sizeof(uint8_t)); if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Notify()"); } void EventFd::Clear() { // Drain the byte(s) written to the wake-up pipe. We can potentially read // more than one byte if several wake-ups have been scheduled. char buffer[16]; ssize_t ret = PERFETTO_EINTR(read(event_handle_.get(), &buffer[0], sizeof(buffer))); if (ret <= 0 && errno != EAGAIN) PERFETTO_DFATAL("EventFd::Clear()"); } #endif } // namespace base } // namespace perfetto // gen_amalgamated begin source: src/base/file_utils.cc // gen_amalgamated begin header: include/perfetto/ext/base/file_utils.h // gen_amalgamated begin header: include/perfetto/base/status.h /* * Copyright (C) 2019 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. */ #ifndef INCLUDE_PERFETTO_BASE_STATUS_H_ #define INCLUDE_PERFETTO_BASE_STATUS_H_ #include // gen_amalgamated expanded: #include "perfetto/base/compiler.h" // gen_amalgamated expanded: #include "perfetto/base/export.h" // gen_amalgamated expanded: #include "perfetto/base/logging.h" namespace perfetto { namespace base { // Represents either the success or the failure message of a function. // This can used as the return type of functions which would usually return an // bool for success or int for errno but also wants to add some string context // (ususally for logging). class PERFETTO_EXPORT_COMPONENT Status { public: Status() : ok_(true) {} explicit Status(std::string msg) : ok_(false), message_(std::move(msg)) { PERFETTO_CHECK(!message_.empty()); } // Copy operations. Status(const Status&) = default; Status& operator=(const Status&) = default; // Move operations. The moved-from state is valid but unspecified. Status(Status&&) noexcept = default; Status& operator=(Status&&) = default; bool ok() const { return ok_; } // When ok() is false this returns the error message. Returns the empty string // otherwise. const std::string& message() const { return message_; } const char* c_message() const { return message_.c_str(); } private: bool ok_ = false; std::string message_; }; // Returns a status object which represents the Ok status. inline Status OkStatus() { return Status(); } PERFETTO_PRINTF_FORMAT(1, 2) Status ErrStatus(const char* format, ...); } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_BASE_STATUS_H_ /* * 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ #define INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ #include // For mode_t & O_RDONLY/RDWR. Exists also on Windows. #include #include #include // gen_amalgamated expanded: #include "perfetto/base/build_config.h" // gen_amalgamated expanded: #include "perfetto/base/export.h" // gen_amalgamated expanded: #include "perfetto/base/status.h" // gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" // gen_amalgamated expanded: #include "perfetto/ext/base/optional.h" // gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" namespace perfetto { namespace base { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) using FileOpenMode = int; #else using FileOpenMode = mode_t; #endif constexpr FileOpenMode kFileModeInvalid = static_cast(-1); bool ReadPlatformHandle(PlatformHandle, std::string* out); bool ReadFileDescriptor(int fd, std::string* out); bool ReadFileStream(FILE* f, std::string* out); bool ReadFile(const std::string& path, std::string* out); // A wrapper around read(2). It deals with Linux vs Windows includes. It also // deals with handling EINTR. Has the same semantics of UNIX's read(2). ssize_t Read(int fd, void* dst, size_t dst_size); // Call write until all data is written or an error is detected. // // man 2 write: // If a write() is interrupted by a signal handler before any bytes are // written, then the call fails with the error EINTR; if it is // interrupted after at least one byte has been written, the call // succeeds, and returns the number of bytes written. ssize_t WriteAll(int fd, const void* buf, size_t count); ssize_t WriteAllHandle(PlatformHandle, const void* buf, size_t count); ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode = kFileModeInvalid); ScopedFstream OpenFstream(const char* path, const char* mode); // This is an alias for close(). It's to avoid leaking Windows.h in headers. // Exported because ScopedFile is used in the /include/ext API by Chromium // component builds. int PERFETTO_EXPORT_COMPONENT CloseFile(int fd); bool FlushFile(int fd); // Returns true if mkdir succeeds, false if it fails (see errno in that case). bool Mkdir(const std::string& path); // Calls rmdir() on UNIX, _rmdir() on Windows. bool Rmdir(const std::string& path); // Wrapper around access(path, F_OK). bool FileExists(const std::string& path); // Gets the extension for a filename. If the file has two extensions, returns // only the last one (foo.pb.gz => .gz). Returns empty string if there is no // extension. std::string GetFileExtension(const std::string& filename); // Puts the path to all files under |dir_path| in |output|, recursively walking // subdirectories. File paths are relative to |dir_path|. Only files are // included, not directories. Path separator is always '/', even on windows (not // '\'). base::Status ListFilesRecursive(const std::string& dir_path, std::vector& output); // Returns the size of the file at `path` or nullopt in case of error. Optional GetFileSize(const std::string& path); } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ /* * 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. */ // gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h" #include #include #include #include #include #include // gen_amalgamated expanded: #include "perfetto/base/build_config.h" // gen_amalgamated expanded: #include "perfetto/base/logging.h" // gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" // gen_amalgamated expanded: #include "perfetto/base/status.h" // gen_amalgamated expanded: #include "perfetto/ext/base/optional.h" // gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" // gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #include #include #include #include #else #include #include #endif namespace perfetto { namespace base { namespace { constexpr size_t kBufSize = 2048; #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall. int CloseFindHandle(HANDLE h) { return FindClose(h) ? 0 : -1; } Optional ToUtf16(const std::string str) { int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), nullptr, 0); if (len < 0) { return base::nullopt; } std::vector tmp; tmp.resize(static_cast::size_type>(len)); len = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), tmp.data(), static_cast(tmp.size())); if (len < 0) { return base::nullopt; } PERFETTO_CHECK(static_cast::size_type>(len) == tmp.size()); return std::wstring(tmp.data(), tmp.size()); } #endif } // namespace ssize_t Read(int fd, void* dst, size_t dst_size) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) return _read(fd, dst, static_cast(dst_size)); #else return PERFETTO_EINTR(read(fd, dst, dst_size)); #endif } bool ReadFileDescriptor(int fd, std::string* out) { // Do not override existing data in string. size_t i = out->size(); struct stat buf {}; if (fstat(fd, &buf) != -1) { if (buf.st_size > 0) out->resize(i + static_cast(buf.st_size)); } ssize_t bytes_read; for (;;) { if (out->size() < i + kBufSize) out->resize(out->size() + kBufSize); bytes_read = Read(fd, &((*out)[i]), kBufSize); if (bytes_read > 0) { i += static_cast(bytes_read); } else { out->resize(i); return bytes_read == 0; } } } bool ReadPlatformHandle(PlatformHandle h, std::string* out) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // Do not override existing data in string. size_t i = out->size(); for (;;) { if (out->size() < i + kBufSize) out->resize(out->size() + kBufSize); DWORD bytes_read = 0; auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr); if (res && bytes_read > 0) { i += static_cast(bytes_read); } else { out->resize(i); const bool is_eof = res && bytes_read == 0; auto err = res ? 0 : GetLastError(); // The "Broken pipe" error on Windows is slighly different than Unix: // On Unix: a "broken pipe" error can happen only on the writer side. On // the reader there is no broken pipe, just a EOF. // On windows: the reader also sees a broken pipe error. // Here we normalize on the Unix behavior, treating broken pipe as EOF. return is_eof || err == ERROR_BROKEN_PIPE; } } #else return ReadFileDescriptor(h, out); #endif } bool ReadFileStream(FILE* f, std::string* out) { return ReadFileDescriptor(fileno(f), out); } bool ReadFile(const std::string& path, std::string* out) { base::ScopedFile fd = base::OpenFile(path, O_RDONLY); if (!fd) return false; return ReadFileDescriptor(*fd, out); } ssize_t WriteAll(int fd, const void* buf, size_t count) { size_t written = 0; while (written < count) { // write() on windows takes an unsigned int size. uint32_t bytes_left = static_cast( std::min(count - written, static_cast(UINT32_MAX))); ssize_t wr = PERFETTO_EINTR( write(fd, static_cast(buf) + written, bytes_left)); if (wr == 0) break; if (wr < 0) return wr; written += static_cast(wr); } return static_cast(written); } ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) DWORD wsize = 0; if (::WriteFile(h, buf, static_cast(count), &wsize, nullptr)) { return wsize; } else { return -1; } #else return WriteAll(h, buf, count); #endif } bool FlushFile(int fd) { PERFETTO_DCHECK(fd != 0); #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) return !PERFETTO_EINTR(fdatasync(fd)); #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) return !PERFETTO_EINTR(_commit(fd)); #else return !PERFETTO_EINTR(fsync(fd)); #endif } bool Mkdir(const std::string& path) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) return _mkdir(path.c_str()) == 0; #else return mkdir(path.c_str(), 0755) == 0; #endif } bool Rmdir(const std::string& path) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) return _rmdir(path.c_str()) == 0; #else return rmdir(path.c_str()) == 0; #endif } int CloseFile(int fd) { return close(fd); } ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) { PERFETTO_DCHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid); #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // Always use O_BINARY on Windows, to avoid silly EOL translations. ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode)); #else // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec. ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode)); #endif return fd; } ScopedFstream OpenFstream(const char* path, const char* mode) { ScopedFstream file; // On Windows fopen interprets filename using the ANSI or OEM codepage but // sqlite3_value_text returns a UTF-8 string. To make sure we interpret the // filename correctly we use _wfopen and a UTF-16 string on windows. #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) auto w_path = ToUtf16(path); auto w_mode = ToUtf16(mode); if (w_path && w_mode) { file.reset(_wfopen(w_path->c_str(), w_mode->c_str())); } #else file.reset(fopen(path, mode)); #endif return file; } bool FileExists(const std::string& path) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) return _access(path.c_str(), 0) == 0; #else return access(path.c_str(), F_OK) == 0; #endif } // Declared in base/platform_handle.h. int ClosePlatformHandle(PlatformHandle handle) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // Make the return value UNIX-style. return CloseHandle(handle) ? 0 : -1; #else return close(handle); #endif } base::Status ListFilesRecursive(const std::string& dir_path, std::vector& output) { std::string root_dir_path = dir_path; if (root_dir_path.back() == '\\') { root_dir_path.back() = '/'; } else if (root_dir_path.back() != '/') { root_dir_path.push_back('/'); } // dir_queue contains full paths to the directories. The paths include the // root_dir_path at the beginning and the trailing slash at the end. std::deque dir_queue; dir_queue.push_back(root_dir_path); while (!dir_queue.empty()) { const std::string cur_dir = std::move(dir_queue.front()); dir_queue.pop_front(); #if PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) return base::ErrStatus("ListFilesRecursive not supported yet"); #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) std::string glob_path = cur_dir + "*"; // + 1 because we also have to count the NULL terminator. if (glob_path.length() + 1 > MAX_PATH) return base::ErrStatus("Directory path %s is too long", dir_path.c_str()); WIN32_FIND_DATAA ffd; base::ScopedResource hFind(FindFirstFileA(glob_path.c_str(), &ffd)); if (!hFind) { // For empty directories, there should be at least one entry '.'. // If FindFirstFileA returns INVALID_HANDLE_VALUE, this means directory // couldn't be accessed. return base::ErrStatus("Failed to open directory %s", cur_dir.c_str()); } do { if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) continue; if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { std::string subdir_path = cur_dir + ffd.cFileName + '/'; dir_queue.push_back(subdir_path); } else { const std::string full_path = cur_dir + ffd.cFileName; PERFETTO_CHECK(full_path.length() > root_dir_path.length()); output.push_back(full_path.substr(root_dir_path.length())); } } while (FindNextFileA(*hFind, &ffd)); #else ScopedDir dir = ScopedDir(opendir(cur_dir.c_str())); if (!dir) { return base::ErrStatus("Failed to open directory %s", cur_dir.c_str()); } for (auto* dirent = readdir(dir.get()); dirent != nullptr; dirent = readdir(dir.get())) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { continue; } if (dirent->d_type == DT_DIR) { dir_queue.push_back(cur_dir + dirent->d_name + '/'); } else if (dirent->d_type == DT_REG) { const std::string full_path = cur_dir + dirent->d_name; PERFETTO_CHECK(full_path.length() > root_dir_path.length()); output.push_back(full_path.substr(root_dir_path.length())); } } #endif } return base::OkStatus(); } std::string GetFileExtension(const std::string& filename) { auto ext_idx = filename.rfind('.'); if (ext_idx == std::string::npos) return std::string(); return filename.substr(ext_idx); } base::Optional GetFileSize(const std::string& file_path) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) HANDLE file = CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (file == INVALID_HANDLE_VALUE) { return nullopt; } LARGE_INTEGER file_size; file_size.QuadPart = 0; BOOL ok = GetFileSizeEx(file, &file_size); CloseHandle(file); if (!ok) { return nullopt; } return static_cast(file_size.QuadPart); #else base::ScopedFile fd(base::OpenFile(file_path, O_RDONLY | O_CLOEXEC)); if (!fd) { return nullopt; } struct stat buf {}; if (fstat(*fd, &buf) == -1) { return nullopt; } return static_cast(buf.st_size); #endif } } // namespace base } // namespace perfetto // gen_amalgamated begin source: src/base/getopt_compat.cc // gen_amalgamated begin header: include/perfetto/ext/base/getopt_compat.h /* * Copyright (C) 2021 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. */ #ifndef INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ #define INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ #include // For std::nullptr_t // No translation units other than base/getopt.h and getopt_compat_unittest.cc // should directly include this file. Use base/getopt.h instead. namespace perfetto { namespace base { namespace getopt_compat { // A tiny getopt() replacement for Windows, which doesn't have . // This implementation is based on the subset of features that we use in the // Perfetto codebase. It doesn't even try to deal with the full surface of GNU's // getopt(). // Limitations: // - getopt_long_only() is not supported. // - optional_argument is not supported. That is extremely subtle and caused us // problems in the past with GNU's getopt. // - It does not reorder non-option arguments. It behaves like MacOS getopt, or // GNU's when POSIXLY_CORRECT=1. // - Doesn't expose optopt or opterr. // - option.flag and longindex are not supported and must be nullptr. enum { no_argument = 0, required_argument = 1, }; struct option { const char* name; int has_arg; std::nullptr_t flag; // Only nullptr is supported. int val; }; extern char* optarg; extern int optind; extern int optopt; extern int opterr; int getopt_long(int argc, char** argv, const char* shortopts, const option* longopts, std::nullptr_t /*longindex is not supported*/); int getopt(int argc, char** argv, const char* shortopts); } // namespace getopt_compat } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ /* * Copyright (C) 2021 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. */ // gen_amalgamated expanded: #include "perfetto/ext/base/getopt_compat.h" #include #include #include #include // gen_amalgamated expanded: #include "perfetto/base/logging.h" namespace perfetto { namespace base { namespace getopt_compat { char* optarg = nullptr; int optind = 0; int optopt = 0; int opterr = 1; namespace { char* nextchar = nullptr; const option* LookupLongOpt(const std::vector