// 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/default_platform.cc // gen_amalgamated begin header: include/perfetto/ext/base/platform.h /* * Copyright (C) 2023 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_PLATFORM_H_ #define INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ namespace perfetto { namespace base { namespace platform { // Executed before entering a syscall (e.g. poll, read, write etc) which might // block. // This is overridden in Google internal builds for dealing with userspace // scheduling. void BeforeMaybeBlockingSyscall(); // Executed after entering a syscall (e.g. poll, read, write etc) which might // block. // This is overridden in Google internal builds for dealing with userspace // scheduling. void AfterMaybeBlockingSyscall(); } // namespace platform } // namespace base } // namespace perfetto #endif // INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ /* * Copyright (C) 2023 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/platform.h" namespace perfetto { namespace base { namespace platform { // This is a no-op outside of Google3 where we have some custom logic to deal // with the userspace scheduler. void BeforeMaybeBlockingSyscall() {} // This is a no-op outside of Google3 where we have some custom logic to deal // with the userspace scheduler. void AfterMaybeBlockingSyscall() {} } // namespace platform } // namespace base } // namespace perfetto // 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/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; return memcmp(data(), other.data(), other.size()) == 0; } bool EndsWith(const StringView& other) const { if (other.size() == 0) return true; if (size() == 0) return false; if (other.size() > size()) return false; size_t off = size() - other.size(); return memcmp(data() + off, other.data(), other.size()) == 0; } 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 #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 = 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 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && !defined(AID_SHELL) // From libcutils' android_filesystem_config.h . #define AID_SHELL 2000 #endif namespace perfetto { namespace base { // The machine ID used in the tracing core. using MachineID = uint32_t; // The default value reserved for the host trace. constexpr MachineID kDefaultMachineID = 0; 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 { namespace internal { extern std::atomic g_cached_page_size; uint32_t GetSysPageSizeSlowpath(); } // namespace internal // Returns the system's page size. Use this when dealing with mmap, madvise and // similar mm-related syscalls. // This function might be called in hot paths. Avoid calling getpagesize() all // the times, in many implementations getpagesize() calls sysconf() which is // not cheap. inline uint32_t GetSysPageSize() { const uint32_t page_size = internal::g_cached_page_size.load(std::memory_order_relaxed); return page_size != 0 ? page_size : internal::GetSysPageSizeSlowpath(); } 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). inline constexpr size_t AlignUp(size_t size, size_t alignment) { return (size + alignment - 1) & ~(alignment - 1); } // TODO(primiano): clean this up and move all existing usages to the constexpr // version above. template constexpr size_t AlignUp(size_t size) { static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2"); return AlignUp(size, alignment); } 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 #include // 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); std::optional Base64Decode(const char* src, size_t src_size); inline std::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); } std::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 std::nullopt; // Decoding error. PERFETTO_CHECK(res <= static_cast(dst.size())); dst.resize(static_cast(res)); return std::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 #include // 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 std::optional CStringToUInt32(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtoul(s, &endptr, base)); return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; } inline std::optional CStringToInt32(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtol(s, &endptr, base)); return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; } // Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000... inline std::optional CStringToInt64(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtoll(s, &endptr, base)); return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; } inline std::optional CStringToUInt64(const char* s, int base = 10) { char* endptr = nullptr; auto value = static_cast(strtoull(s, &endptr, base)); return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; } double StrToD(const char* nptr, char** endptr); inline std::optional CStringToDouble(const char* s) { char* endptr = nullptr; double value = StrToD(s, &endptr); std::optional result(std::nullopt); if (*s != '\0' && *endptr == '\0') result = value; return result; } inline std::optional StringToUInt32(const std::string& s, int base = 10) { return CStringToUInt32(s.c_str(), base); } inline std::optional StringToInt32(const std::string& s, int base = 10) { return CStringToInt32(s.c_str(), base); } inline std::optional StringToUInt64(const std::string& s, int base = 10) { return CStringToUInt64(s.c_str(), base); } inline std::optional StringToInt64(const std::string& s, int base = 10) { return CStringToInt64(s.c_str(), base); } inline std::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 TrimWhitespace(const std::string& str); 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); #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) bool WideToUTF8(const std::wstring& source, std::string& output); bool UTF8ToWide(const std::string& source, std::wstring& output); #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // 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 std::nullopt if the offset points to // line break character or exceeds string length. std::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_; } char* mutable_data() { return buf_; } 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 InstallCtrlCHandler(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 InstallCtrlCHandler(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/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 #include #include #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). // // Similar to absl::Status, an optional "payload" can also be included with more // context about the error. This allows passing additional metadata about the // error (e.g. location of errors, potential mitigations etc). 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(); } ////////////////////////////////////////////////////////////////////////////// // Payload Management APIs ////////////////////////////////////////////////////////////////////////////// // Payloads can be attached to error statuses to provide additional context. // // Payloads are (key, value) pairs, where the key is a string acting as a // unique "type URL" and the value is an opaque string. The "type URL" should // be unique, follow the format of a URL and, ideally, documentation on how to // interpret its associated data should be available. // // To attach a payload to a status object, call `Status::SetPayload()`. // Similarly, to extract the payload from a status, call // `Status::GetPayload()`. // // Note: the payload APIs are only meaningful to call when the status is an // error. Otherwise, all methods are noops. // Gets the payload for the given |type_url| if one exists. // // Will always return std::nullopt if |ok()|. std::optional GetPayload(std::string_view type_url) const; // Sets the payload for the given key. The key should // // Will always do nothing if |ok()|. void SetPayload(std::string_view type_url, std::string value); // Erases the payload for the given string and returns true if the payload // existed and was erased. // // Will always do nothing if |ok()|. bool ErasePayload(std::string_view type_url); private: struct Payload { std::string type_url; std::string payload; }; bool ok_ = false; std::string message_; std::vector payloads_; }; // 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 #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/utils.h" namespace perfetto { namespace base { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) using FileOpenMode = int; inline constexpr char kDevNull[] = "NUL"; #else using FileOpenMode = mode_t; inline constexpr char kDevNull[] = "/dev/null"; #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); // Sets |path|'s owner group to |group_name| and permission mode bits to // |mode_bits|. base::Status SetFilePermissions(const std::string& path, const std::string& group_name, const std::string& mode_bits); // Returns the size of the file located at |path|, or nullopt in case of error. std::optional GetFileSize(const std::string& path); // Returns the size of the open file |fd|, or nullopt in case of error. std::optional GetFileSize(PlatformHandle fd); } // 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 #include // 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" // gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" // gen_amalgamated expanded: #include "perfetto/base/status.h" // gen_amalgamated expanded: #include "perfetto/ext/base/platform.h" // gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" // gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h" // gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #include #include #include #include #else #include #include #endif #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) #define PERFETTO_SET_FILE_PERMISSIONS #include #include #include #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; } std::optional ToUtf16(const std::string str) { int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), nullptr, 0); if (len < 0) { return std::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 std::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) { ssize_t ret; platform::BeforeMaybeBlockingSyscall(); #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ret = _read(fd, dst, static_cast(dst_size)); #else ret = PERFETTO_EINTR(read(fd, dst, dst_size)); #endif platform::AfterMaybeBlockingSyscall(); return ret; } 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))); platform::BeforeMaybeBlockingSyscall(); ssize_t wr = PERFETTO_EINTR( write(fd, static_cast(buf) + written, bytes_left)); platform::AfterMaybeBlockingSyscall(); 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) { // If a new file might be created, ensure that the permissions for the new // file are explicitly specified. PERFETTO_CHECK((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::Status SetFilePermissions(const std::string& file_path, const std::string& group_name_or_id, const std::string& mode_bits) { #ifdef PERFETTO_SET_FILE_PERMISSIONS PERFETTO_CHECK(!file_path.empty()); PERFETTO_CHECK(!group_name_or_id.empty()); // Default |group_id| to -1 for not changing the group ownership. gid_t group_id = static_cast(-1); auto maybe_group_id = base::StringToUInt32(group_name_or_id); if (maybe_group_id) { // A numerical group ID. group_id = *maybe_group_id; } else { // A group name. struct group* file_group = nullptr; // Query the group ID of |group|. do { file_group = getgrnam(group_name_or_id.c_str()); } while (file_group == nullptr && errno == EINTR); if (file_group == nullptr) { return base::ErrStatus("Failed to get group information of %s ", group_name_or_id.c_str()); } group_id = file_group->gr_gid; } if (PERFETTO_EINTR(chown(file_path.c_str(), geteuid(), group_id))) { return base::ErrStatus("Failed to chown %s ", file_path.c_str()); } // |mode| accepts values like "0660" as "rw-rw----" mode bits. auto mode_value = base::StringToInt32(mode_bits, 8); if (!(mode_bits.size() == 4 && mode_value.has_value())) { return base::ErrStatus( "The chmod mode bits must be a 4-digit octal number, e.g. 0660"); } if (PERFETTO_EINTR( chmod(file_path.c_str(), static_cast(mode_value.value())))) { return base::ErrStatus("Failed to chmod %s", file_path.c_str()); } return base::OkStatus(); #else base::ignore_result(file_path); base::ignore_result(group_name_or_id); base::ignore_result(mode_bits); return base::ErrStatus( "Setting file permissions is not supported on this platform"); #endif } std::optional GetFileSize(const std::string& file_path) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) // This does not use base::OpenFile to avoid getting an exclusive lock. base::ScopedPlatformHandle fd( CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); #else base::ScopedFile fd(base::OpenFile(file_path, O_RDONLY | O_CLOEXEC)); #endif if (!fd) { return std::nullopt; } return GetFileSize(*fd); } std::optional GetFileSize(PlatformHandle fd) { #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) LARGE_INTEGER file_size; file_size.QuadPart = 0; if (!GetFileSizeEx(fd, &file_size)) { return std::nullopt; } static_assert(sizeof(decltype(file_size.QuadPart)) <= sizeof(uint64_t)); return static_cast(file_size.QuadPart); #else struct stat buf {}; if (fstat(fd, &buf) == -1) { return std::nullopt; } static_assert(sizeof(decltype(buf.st_size)) <= sizeof(uint64_t)); 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