diff --git a/utils/arcvm-time-sync-app/.gitignore b/utils/arcvm-time-sync-app/.gitignore
new file mode 100644
index 0000000..5c26ee8
--- /dev/null
+++ b/utils/arcvm-time-sync-app/.gitignore
@@ -0,0 +1,20 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+/.idea/gradle.xml
+/.idea/misc.xml
+/.idea/compiler.xml
+/.idea/vcs.xml
+/.idea/.name
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/utils/arcvm-time-sync-app/.idea/.gitignore b/utils/arcvm-time-sync-app/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/utils/arcvm-time-sync-app/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/utils/arcvm-time-sync-app/app/.gitignore b/utils/arcvm-time-sync-app/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/build.gradle b/utils/arcvm-time-sync-app/app/build.gradle
new file mode 100644
index 0000000..094944c
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/build.gradle
@@ -0,0 +1,51 @@
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ compileSdk 30
+
+ defaultConfig {
+ applicationId "com.google.perfettoguesttimesync"
+ minSdk 28
+ targetSdk 30
+ versionCode 4
+ versionName "1.3"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ externalNativeBuild {
+ cmake {
+ cppFlags ''
+ }
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ externalNativeBuild {
+ cmake {
+ path file('src/main/cpp/CMakeLists.txt')
+ version '3.10.2'
+ }
+ }
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+dependencies {
+
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:2.0.4'
+ testImplementation 'junit:junit:4.+'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/proguard-rules.pro b/utils/arcvm-time-sync-app/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/release/app-release.apk b/utils/arcvm-time-sync-app/app/release/app-release.apk
new file mode 100644
index 0000000..816c658
Binary files /dev/null and b/utils/arcvm-time-sync-app/app/release/app-release.apk differ
diff --git a/utils/arcvm-time-sync-app/app/release/output-metadata.json b/utils/arcvm-time-sync-app/app/release/output-metadata.json
new file mode 100644
index 0000000..1717f79
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/release/output-metadata.json
@@ -0,0 +1,20 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "com.google.perfettoguesttimesync",
+ "variantName": "release",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "versionCode": 4,
+ "versionName": "1.3",
+ "outputFile": "app-release.apk"
+ }
+ ],
+ "elementType": "File"
+}
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/src/main/AndroidManifest.xml b/utils/arcvm-time-sync-app/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6a17fc6
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/src/main/cpp/CMakeLists.txt b/utils/arcvm-time-sync-app/app/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..da39c22
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,51 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.10.2)
+
+# Declares and names the project.
+
+project("perfettoguesttimesync")
+
+find_package(Threads)
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+add_library( # Sets the name of the library.
+ perfettoguesttimesync
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # Provides a relative path to your source file(s).
+ native-lib.cpp
+ perfetto.cc)
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+find_library( # Sets the name of the path variable.
+ log-lib
+
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ log)
+
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+target_link_libraries( # Specifies the target library.
+ perfettoguesttimesync
+
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib})
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/src/main/cpp/native-lib.cpp b/utils/arcvm-time-sync-app/app/src/main/cpp/native-lib.cpp
new file mode 100644
index 0000000..e643c09
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/src/main/cpp/native-lib.cpp
@@ -0,0 +1,108 @@
+// Copyright 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.
+#include
+#include
+#include
+#include
+#include
+
+#if defined(_M_IA64) || defined(_M_IX86) || defined(__ia64__) || \
+ defined(__i386__) || defined(__amd64__) || defined(__x86_64__) || \
+ defined(_M_AMD64)
+#define HAS_RDTSC
+#ifdef _MSC_VER
+#include
+#else
+#include
+#endif
+#endif
+#if defined(__aarch64__)
+#define HAS_CNTCVT
+#endif
+
+#include "perfetto.h"
+
+PERFETTO_DEFINE_CATEGORIES(
+ perfetto::Category("cros")
+ .SetDescription("Chrome OS guest time sync events"));
+
+PERFETTO_TRACK_EVENT_STATIC_STORAGE();
+
+static std::once_flag perfetto_once;
+static std::thread* bg_thread = nullptr;
+
+static inline uint64_t get_cpu_ticks() {
+#if defined(HAS_RDTSC)
+ return __rdtsc();
+#elif defined(HAS_CNTCVT)
+ uint64_t vct;
+ asm volatile("mrs %0, cntvct_el0" : "=r"(vct));
+ return vct;
+#else
+ return 0;
+#endif
+}
+
+static inline uint64_t get_timestamp_ns(clockid_t cid) {
+ struct timespec ts = {};
+ clock_gettime(cid, &ts);
+ return static_cast(ts.tv_sec * 1000000000LL + ts.tv_nsec);
+}
+
+void perfetto_annotate_time_sync(const perfetto::EventContext& perfetto) {
+ uint64_t boot_time = get_timestamp_ns(CLOCK_BOOTTIME);
+ uint64_t cpu_time = get_cpu_ticks();
+ uint64_t monotonic_time = get_timestamp_ns(CLOCK_MONOTONIC);
+ // Read again to avoid cache miss overhead.
+ boot_time = get_timestamp_ns(CLOCK_BOOTTIME);
+ cpu_time = get_cpu_ticks();
+ monotonic_time = get_timestamp_ns(CLOCK_MONOTONIC);
+
+ auto* dbg = perfetto.event()->add_debug_annotations();
+ dbg->set_name("clock_sync_boottime");
+ dbg->set_uint_value(boot_time);
+ dbg = perfetto.event()->add_debug_annotations();
+ dbg->set_name("clock_sync_monotonic");
+ dbg->set_uint_value(monotonic_time);
+ dbg = perfetto.event()->add_debug_annotations();
+ dbg->set_name("clock_sync_cputime");
+ dbg->set_uint_value(cpu_time);
+}
+
+void tick_forever() {
+ for(;;) {
+ usleep(100000);
+ TRACE_EVENT(
+ "cros", "guest_clock_sync",
+ [&](perfetto::EventContext p) { perfetto_annotate_time_sync(p); });
+ }
+}
+
+void init_perfetto()
+{
+ std::call_once(perfetto_once, [](){
+ perfetto::TracingInitArgs args;
+ args.backends |= perfetto::kSystemBackend;
+ perfetto::Tracing::Initialize(args);
+ perfetto::TrackEvent::Register();
+ bg_thread = new std::thread(tick_forever);
+ });
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_perfettoguesttimesync_TimeTrace_perfettoInit(
+ JNIEnv* env,
+ jobject /* this */) {
+ init_perfetto();
+}
\ No newline at end of file
diff --git a/utils/arcvm-time-sync-app/app/src/main/cpp/perfetto.cc b/utils/arcvm-time-sync-app/app/src/main/cpp/perfetto.cc
new file mode 100644
index 0000000..cfc99bf
--- /dev/null
+++ b/utils/arcvm-time-sync-app/app/src/main/cpp/perfetto.cc
@@ -0,0 +1,69869 @@
+// 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
+#if !defined(GOOGLE_PROTOBUF_NO_RTTI)
+#define GOOGLE_PROTOBUF_NO_RTTI
+#endif
+#if !defined(GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER)
+#define GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+#endif
+#include "perfetto.h"
+// 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 PERFETTO_EXPORT 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 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_
+// gen_amalgamated begin header: include/perfetto/ext/base/utils.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_
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#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
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+using uid_t = unsigned int;
+#if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
+using pid_t = unsigned int;
+#endif
+#if defined(_WIN64)
+using ssize_t = int64_t;
+#else
+using ssize_t = long;
+#endif
+#endif
+
+namespace perfetto {
+namespace base {
+
+constexpr uid_t kInvalidUid = static_cast(-1);
+constexpr pid_t kInvalidPid = static_cast(-1);
+
+// 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& array) {
+ return sizeof(array) / sizeof(array[0]);
+}
+
+// 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);
+
+// 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 and exit(0).
+// Child: redirects stdio onto /dev/null and chdirs into .
+void Daemonize();
+
+// 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();
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_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/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 = 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 = 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
+/*
+ * 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
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.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;
+#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);
+
+// 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 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);
+
+} // 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
+
+// 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/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include
+#include
+#include
+#else
+#include
+#include
+#endif
+
+namespace perfetto {
+namespace base {
+namespace {
+constexpr size_t kBufSize = 2048;
+}
+
+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;
+}
+
+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
+}
+
+} // 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