Merge "Remove build dependency of surfaceflinger on libinput" into main
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 826a8db..6b9a0a0 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -4197,14 +4197,14 @@
}
int read_file_as_long(const char *path, long int *output) {
- int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
- if (fd < 0) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+ if (fd.get() < 0) {
int err = errno;
MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
return -1;
}
char buffer[50];
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer, sizeof(buffer)));
if (bytes_read == -1) {
MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
return -2;
diff --git a/cmds/evemu-record/main.rs b/cmds/evemu-record/main.rs
index c30c00f..db3fd77 100644
--- a/cmds/evemu-record/main.rs
+++ b/cmds/evemu-record/main.rs
@@ -120,7 +120,7 @@
fn print_in_8_byte_chunks(
output: &mut impl Write,
prefix: &str,
- data: &Vec<u8>,
+ data: &[u8],
) -> Result<(), io::Error> {
for (i, byte) in data.iter().enumerate() {
if i % 8 == 0 {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 35cea81..1ffdad5 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2980,6 +2980,7 @@
uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);
if (!data && desired > mDataCapacity) {
+ LOG_ALWAYS_FATAL("out of memory");
mError = NO_MEMORY;
return NO_MEMORY;
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index f4c32f2..6b8bc01 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -177,6 +177,10 @@
],
generated_sources: ["libinput_cxx_bridge_code"],
+ lto: {
+ never: true,
+ },
+
shared_libs: [
"libbase",
],
diff --git a/libs/tracing_perfetto/.clang-format b/libs/tracing_perfetto/.clang-format
new file mode 100644
index 0000000..f397454
--- /dev/null
+++ b/libs/tracing_perfetto/.clang-format
@@ -0,0 +1,12 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 80
+ContinuationIndentWidth: 4
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+UseTab: Never
+PenaltyExcessCharacter: 32
\ No newline at end of file
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
new file mode 100644
index 0000000..3a4c869
--- /dev/null
+++ b/libs/tracing_perfetto/Android.bp
@@ -0,0 +1,49 @@
+// Copyright 2024 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+ name: "libtracing_perfetto",
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-enum-compare",
+ "-Wno-unused-function",
+ ],
+
+ srcs: [
+ "tracing_perfetto.cpp",
+ "tracing_perfetto_internal.cpp",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libperfetto_c",
+ "android.os.flags-aconfig-cc-host",
+ ],
+
+ host_supported: true,
+}
diff --git a/libs/tracing_perfetto/OWNERS b/libs/tracing_perfetto/OWNERS
new file mode 100644
index 0000000..e2d4b46
--- /dev/null
+++ b/libs/tracing_perfetto/OWNERS
@@ -0,0 +1,2 @@
+zezeozue@google.com
+biswarupp@google.com
\ No newline at end of file
diff --git a/libs/tracing_perfetto/include/trace_categories.h b/libs/tracing_perfetto/include/trace_categories.h
new file mode 100644
index 0000000..6d4168b
--- /dev/null
+++ b/libs/tracing_perfetto/include/trace_categories.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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 TRACE_CATEGORIES_H
+#define TRACE_CATEGORIES_H
+
+/**
+ * Keep these in sync with frameworks/base/core/java/android/os/Trace.java.
+ */
+#define TRACE_CATEGORY_ALWAYS (1 << 0)
+#define TRACE_CATEGORY_GRAPHICS (1 << 1)
+#define TRACE_CATEGORY_INPUT (1 << 2)
+#define TRACE_CATEGORY_VIEW (1 << 3)
+#define TRACE_CATEGORY_WEBVIEW (1 << 4)
+#define TRACE_CATEGORY_WINDOW_MANAGER (1 << 5)
+#define TRACE_CATEGORY_ACTIVITY_MANAGER (1 << 6)
+#define TRACE_CATEGORY_SYNC_MANAGER (1 << 7)
+#define TRACE_CATEGORY_AUDIO (1 << 8)
+#define TRACE_CATEGORY_VIDEO (1 << 9)
+#define TRACE_CATEGORY_CAMERA (1 << 10)
+#define TRACE_CATEGORY_HAL (1 << 11)
+#define TRACE_CATEGORY_APP (1 << 12)
+#define TRACE_CATEGORY_RESOURCES (1 << 13)
+#define TRACE_CATEGORY_DALVIK (1 << 14)
+#define TRACE_CATEGORY_RS (1 << 15)
+#define TRACE_CATEGORY_BIONIC (1 << 16)
+#define TRACE_CATEGORY_POWER (1 << 17)
+#define TRACE_CATEGORY_PACKAGE_MANAGER (1 << 18)
+#define TRACE_CATEGORY_SYSTEM_SERVER (1 << 19)
+#define TRACE_CATEGORY_DATABASE (1 << 20)
+#define TRACE_CATEGORY_NETWORK (1 << 21)
+#define TRACE_CATEGORY_ADB (1 << 22)
+#define TRACE_CATEGORY_VIBRATOR (1 << 23)
+#define TRACE_CATEGORY_AIDL (1 << 24)
+#define TRACE_CATEGORY_NNAPI (1 << 25)
+#define TRACE_CATEGORY_RRO (1 << 26)
+#define TRACE_CATEGORY_THERMAL (1 << 27)
+
+// Allow all categories except TRACE_CATEGORY_APP
+#define TRACE_CATEGORIES \
+ TRACE_CATEGORY_ALWAYS | TRACE_CATEGORY_GRAPHICS | TRACE_CATEGORY_INPUT | \
+ TRACE_CATEGORY_VIEW | TRACE_CATEGORY_WEBVIEW | \
+ TRACE_CATEGORY_WINDOW_MANAGER | TRACE_CATEGORY_ACTIVITY_MANAGER | \
+ TRACE_CATEGORY_SYNC_MANAGER | TRACE_CATEGORY_AUDIO | \
+ TRACE_CATEGORY_VIDEO | TRACE_CATEGORY_CAMERA | TRACE_CATEGORY_HAL | \
+ TRACE_CATEGORY_RESOURCES | TRACE_CATEGORY_DALVIK | TRACE_CATEGORY_RS | \
+ TRACE_CATEGORY_BIONIC | TRACE_CATEGORY_POWER | \
+ TRACE_CATEGORY_PACKAGE_MANAGER | TRACE_CATEGORY_SYSTEM_SERVER | \
+ TRACE_CATEGORY_DATABASE | TRACE_CATEGORY_NETWORK | TRACE_CATEGORY_ADB | \
+ TRACE_CATEGORY_VIBRATOR | TRACE_CATEGORY_AIDL | TRACE_CATEGORY_NNAPI | \
+ TRACE_CATEGORY_RRO | TRACE_CATEGORY_THERMAL
+#endif // TRACE_CATEGORIES_H
diff --git a/libs/tracing_perfetto/include/trace_result.h b/libs/tracing_perfetto/include/trace_result.h
new file mode 100644
index 0000000..f7581fc
--- /dev/null
+++ b/libs/tracing_perfetto/include/trace_result.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2024 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 TRACE_RESULT_H
+#define TRACE_RESULT_H
+
+namespace tracing_perfetto {
+
+enum class Result {
+ SUCCESS,
+ NOT_SUPPORTED,
+ INVALID_INPUT,
+};
+
+}
+
+#endif // TRACE_RESULT_H
diff --git a/libs/tracing_perfetto/include/tracing_perfetto.h b/libs/tracing_perfetto/include/tracing_perfetto.h
new file mode 100644
index 0000000..4e3c83f
--- /dev/null
+++ b/libs/tracing_perfetto/include/tracing_perfetto.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2024 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 TRACING_PERFETTO_H
+#define TRACING_PERFETTO_H
+
+#include <stdint.h>
+
+#include "trace_result.h"
+
+namespace tracing_perfetto {
+
+void registerWithPerfetto(bool test = false);
+
+Result traceBegin(uint64_t category, const char* name);
+
+Result traceEnd(uint64_t category);
+
+Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
+
+Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
+
+Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+ const char* trackName, int32_t cookie);
+
+Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+ int32_t cookie);
+
+Result traceInstant(uint64_t category, const char* name);
+
+Result traceInstantForTrack(uint64_t category, const char* trackName,
+ const char* name);
+
+Result traceCounter(uint64_t category, const char* name, int64_t value);
+
+uint64_t getEnabledCategories();
+
+} // namespace tracing_perfetto
+
+#endif // TRACING_PERFETTO_H
diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp
new file mode 100644
index 0000000..a35b0e0
--- /dev/null
+++ b/libs/tracing_perfetto/tests/Android.bp
@@ -0,0 +1,45 @@
+// Copyright 2024 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "libtracing_perfetto_tests",
+ static_libs: [
+ "libflagtest",
+ "libgmock",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "android.os.flags-aconfig-cc-host",
+ "libbase",
+ "libperfetto_c",
+ "libtracing_perfetto",
+ ],
+ srcs: [
+ "tracing_perfetto_test.cpp",
+ "utils.cpp",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
new file mode 100644
index 0000000..7716b9a
--- /dev/null
+++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2024 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 "tracing_perfetto.h"
+
+#include <thread>
+
+#include <android_os.h>
+#include <flag_macros.h>
+
+#include "gtest/gtest.h"
+#include "perfetto/public/abi/data_source_abi.h"
+#include "perfetto/public/abi/heap_buffer.h"
+#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/abi/tracing_session_abi.h"
+#include "perfetto/public/abi/track_event_abi.h"
+#include "perfetto/public/data_source.h"
+#include "perfetto/public/pb_decoder.h"
+#include "perfetto/public/producer.h"
+#include "perfetto/public/protos/config/trace_config.pzc.h"
+#include "perfetto/public/protos/trace/interned_data/interned_data.pzc.h"
+#include "perfetto/public/protos/trace/test_event.pzc.h"
+#include "perfetto/public/protos/trace/trace.pzc.h"
+#include "perfetto/public/protos/trace/trace_packet.pzc.h"
+#include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h"
+#include "perfetto/public/protos/trace/track_event/track_descriptor.pzc.h"
+#include "perfetto/public/protos/trace/track_event/track_event.pzc.h"
+#include "perfetto/public/protos/trace/trigger.pzc.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+#include "trace_categories.h"
+#include "utils.h"
+
+namespace tracing_perfetto {
+
+using ::perfetto::shlib::test_utils::AllFieldsWithId;
+using ::perfetto::shlib::test_utils::FieldView;
+using ::perfetto::shlib::test_utils::IdFieldView;
+using ::perfetto::shlib::test_utils::MsgField;
+using ::perfetto::shlib::test_utils::PbField;
+using ::perfetto::shlib::test_utils::StringField;
+using ::perfetto::shlib::test_utils::TracingSession;
+using ::perfetto::shlib::test_utils::VarIntField;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::UnorderedElementsAre;
+
+const auto PERFETTO_SDK_TRACING = ACONFIG_FLAG(android::os, perfetto_sdk_tracing);
+
+class TracingPerfettoTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ tracing_perfetto::registerWithPerfetto(true /* test */);
+ }
+};
+
+// TODO(b/303199244): Add tests for all the library functions.
+
+TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstant,
+ REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
+ TracingSession tracing_session =
+ TracingSession::Builder().set_data_source_name("track_event").Build();
+ tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, "");
+
+ tracing_session.StopBlocking();
+ std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ bool found = false;
+ for (struct PerfettoPbDecoderField trace_field : FieldView(data)) {
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ if (track_event.size() == 0) {
+ continue;
+ }
+ found = true;
+ IdFieldView cat_iid_fields(
+ track_event.front(),
+ perfetto_protos_TrackEvent_category_iids_field_number);
+ ASSERT_THAT(cat_iid_fields, ElementsAre(VarIntField(_)));
+ uint64_t cat_iid = cat_iid_fields.front().value.integer64;
+ EXPECT_THAT(
+ trace_field,
+ AllFieldsWithId(
+ perfetto_protos_TracePacket_interned_data_field_number,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_InternedData_event_categories_field_number,
+ ElementsAre(MsgField(UnorderedElementsAre(
+ PbField(perfetto_protos_EventCategory_iid_field_number,
+ VarIntField(cat_iid)),
+ PbField(perfetto_protos_EventCategory_name_field_number,
+ StringField("input")))))))));
+ }
+ EXPECT_TRUE(found);
+}
+
+} // namespace tracing_perfetto
\ No newline at end of file
diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp
new file mode 100644
index 0000000..9c42028
--- /dev/null
+++ b/libs/tracing_perfetto/tests/utils.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// Copied from //external/perfetto/src/shared_lib/test/utils.cc
+
+#include "utils.h"
+
+#include "perfetto/public/abi/heap_buffer.h"
+#include "perfetto/public/pb_msg.h"
+#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/protos/config/data_source_config.pzc.h"
+#include "perfetto/public/protos/config/trace_config.pzc.h"
+#include "perfetto/public/protos/config/track_event/track_event_config.pzc.h"
+#include "perfetto/public/tracing_session.h"
+
+namespace perfetto {
+namespace shlib {
+namespace test_utils {
+namespace {
+
+std::string ToHexChars(uint8_t val) {
+ std::string ret;
+ uint8_t high_nibble = (val & 0xF0) >> 4;
+ uint8_t low_nibble = (val & 0xF);
+ static const char hex_chars[] = "0123456789ABCDEF";
+ ret.push_back(hex_chars[high_nibble]);
+ ret.push_back(hex_chars[low_nibble]);
+ return ret;
+}
+
+} // namespace
+
+TracingSession TracingSession::Builder::Build() {
+ struct PerfettoPbMsgWriter writer;
+ struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer);
+
+ struct perfetto_protos_TraceConfig cfg;
+ PerfettoPbMsgInit(&cfg.msg, &writer);
+
+ {
+ struct perfetto_protos_TraceConfig_BufferConfig buffers;
+ perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers);
+
+ perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024);
+
+ perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers);
+ }
+
+ {
+ struct perfetto_protos_TraceConfig_DataSource data_sources;
+ perfetto_protos_TraceConfig_begin_data_sources(&cfg, &data_sources);
+
+ {
+ struct perfetto_protos_DataSourceConfig ds_cfg;
+ perfetto_protos_TraceConfig_DataSource_begin_config(&data_sources,
+ &ds_cfg);
+
+ perfetto_protos_DataSourceConfig_set_cstr_name(&ds_cfg,
+ data_source_name_.c_str());
+ if (!enabled_categories_.empty() && !disabled_categories_.empty()) {
+ perfetto_protos_TrackEventConfig te_cfg;
+ perfetto_protos_DataSourceConfig_begin_track_event_config(&ds_cfg,
+ &te_cfg);
+ for (const std::string& cat : enabled_categories_) {
+ perfetto_protos_TrackEventConfig_set_enabled_categories(
+ &te_cfg, cat.data(), cat.size());
+ }
+ for (const std::string& cat : disabled_categories_) {
+ perfetto_protos_TrackEventConfig_set_disabled_categories(
+ &te_cfg, cat.data(), cat.size());
+ }
+ perfetto_protos_DataSourceConfig_end_track_event_config(&ds_cfg,
+ &te_cfg);
+ }
+
+ perfetto_protos_TraceConfig_DataSource_end_config(&data_sources, &ds_cfg);
+ }
+
+ perfetto_protos_TraceConfig_end_data_sources(&cfg, &data_sources);
+ }
+ size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
+ std::unique_ptr<uint8_t[]> ser(new uint8_t[cfg_size]);
+ PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size);
+ PerfettoHeapBufferDestroy(hb, &writer.writer);
+
+ struct PerfettoTracingSessionImpl* ts =
+ PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS);
+
+ PerfettoTracingSessionSetup(ts, ser.get(), cfg_size);
+
+ PerfettoTracingSessionStartBlocking(ts);
+
+ return TracingSession::Adopt(ts);
+}
+
+TracingSession TracingSession::Adopt(struct PerfettoTracingSessionImpl* session) {
+ TracingSession ret;
+ ret.session_ = session;
+ ret.stopped_ = std::make_unique<WaitableEvent>();
+ PerfettoTracingSessionSetStopCb(
+ ret.session_,
+ [](struct PerfettoTracingSessionImpl*, void* arg) {
+ static_cast<WaitableEvent*>(arg)->Notify();
+ },
+ ret.stopped_.get());
+ return ret;
+}
+
+TracingSession::TracingSession(TracingSession&& other) noexcept {
+ session_ = other.session_;
+ other.session_ = nullptr;
+ stopped_ = std::move(other.stopped_);
+ other.stopped_ = nullptr;
+}
+
+TracingSession::~TracingSession() {
+ if (!session_) {
+ return;
+ }
+ if (!stopped_->IsNotified()) {
+ PerfettoTracingSessionStopBlocking(session_);
+ stopped_->WaitForNotification();
+ }
+ PerfettoTracingSessionDestroy(session_);
+}
+
+bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
+ WaitableEvent notification;
+ bool result;
+ auto* cb = new std::function<void(bool)>([&](bool success) {
+ result = success;
+ notification.Notify();
+ });
+ PerfettoTracingSessionFlushAsync(
+ session_, timeout_ms,
+ [](PerfettoTracingSessionImpl*, bool success, void* user_arg) {
+ auto* f = reinterpret_cast<std::function<void(bool)>*>(user_arg);
+ (*f)(success);
+ delete f;
+ },
+ cb);
+ notification.WaitForNotification();
+ return result;
+}
+
+void TracingSession::WaitForStopped() {
+ stopped_->WaitForNotification();
+}
+
+void TracingSession::StopBlocking() {
+ PerfettoTracingSessionStopBlocking(session_);
+}
+
+std::vector<uint8_t> TracingSession::ReadBlocking() {
+ std::vector<uint8_t> data;
+ PerfettoTracingSessionReadTraceBlocking(
+ session_,
+ [](struct PerfettoTracingSessionImpl*, const void* trace_data,
+ size_t size, bool, void* user_arg) {
+ auto& dst = *static_cast<std::vector<uint8_t>*>(user_arg);
+ auto* src = static_cast<const uint8_t*>(trace_data);
+ dst.insert(dst.end(), src, src + size);
+ },
+ &data);
+ return data;
+}
+
+} // namespace test_utils
+} // namespace shlib
+} // namespace perfetto
+
+void PrintTo(const PerfettoPbDecoderField& field, std::ostream* pos) {
+ std::ostream& os = *pos;
+ PerfettoPbDecoderStatus status =
+ static_cast<PerfettoPbDecoderStatus>(field.status);
+ switch (status) {
+ case PERFETTO_PB_DECODER_ERROR:
+ os << "MALFORMED PROTOBUF";
+ break;
+ case PERFETTO_PB_DECODER_DONE:
+ os << "DECODER DONE";
+ break;
+ case PERFETTO_PB_DECODER_OK:
+ switch (field.wire_type) {
+ case PERFETTO_PB_WIRE_TYPE_DELIMITED:
+ os << "\"";
+ for (size_t i = 0; i < field.value.delimited.len; i++) {
+ os << perfetto::shlib::test_utils::ToHexChars(
+ field.value.delimited.start[i])
+ << " ";
+ }
+ os << "\"";
+ break;
+ case PERFETTO_PB_WIRE_TYPE_VARINT:
+ os << "varint: " << field.value.integer64;
+ break;
+ case PERFETTO_PB_WIRE_TYPE_FIXED32:
+ os << "fixed32: " << field.value.integer32;
+ break;
+ case PERFETTO_PB_WIRE_TYPE_FIXED64:
+ os << "fixed64: " << field.value.integer64;
+ break;
+ }
+ break;
+ }
+}
diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h
new file mode 100644
index 0000000..4353554
--- /dev/null
+++ b/libs/tracing_perfetto/tests/utils.h
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// Copied from //external/perfetto/src/shared_lib/test/utils.h
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <cassert>
+#include <condition_variable>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <mutex>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-more-matchers.h"
+#include "gtest/gtest-matchers.h"
+#include "gtest/gtest.h"
+#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/tracing_session.h"
+
+// Pretty printer for gtest
+void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
+
+namespace perfetto {
+namespace shlib {
+namespace test_utils {
+
+class WaitableEvent {
+ public:
+ WaitableEvent() = default;
+ void Notify() {
+ std::unique_lock<std::mutex> lock(m_);
+ notified_ = true;
+ cv_.notify_one();
+ }
+ bool WaitForNotification() {
+ std::unique_lock<std::mutex> lock(m_);
+ cv_.wait(lock, [this] { return notified_; });
+ return notified_;
+ }
+ bool IsNotified() {
+ std::unique_lock<std::mutex> lock(m_);
+ return notified_;
+ }
+
+ private:
+ std::mutex m_;
+ std::condition_variable cv_;
+ bool notified_ = false;
+};
+
+class TracingSession {
+ public:
+ class Builder {
+ public:
+ Builder() = default;
+ Builder& set_data_source_name(std::string data_source_name) {
+ data_source_name_ = std::move(data_source_name);
+ return *this;
+ }
+ Builder& add_enabled_category(std::string category) {
+ enabled_categories_.push_back(std::move(category));
+ return *this;
+ }
+ Builder& add_disabled_category(std::string category) {
+ disabled_categories_.push_back(std::move(category));
+ return *this;
+ }
+ TracingSession Build();
+
+ private:
+ std::string data_source_name_;
+ std::vector<std::string> enabled_categories_;
+ std::vector<std::string> disabled_categories_;
+ };
+
+ static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
+
+ TracingSession(TracingSession&&) noexcept;
+
+ ~TracingSession();
+
+ struct PerfettoTracingSessionImpl* session() const {
+ return session_;
+ }
+
+ bool FlushBlocking(uint32_t timeout_ms);
+ void WaitForStopped();
+ void StopBlocking();
+ std::vector<uint8_t> ReadBlocking();
+
+ private:
+ TracingSession() = default;
+ struct PerfettoTracingSessionImpl* session_;
+ std::unique_ptr<WaitableEvent> stopped_;
+};
+
+template <typename FieldSkipper>
+class FieldViewBase {
+ public:
+ class Iterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const PerfettoPbDecoderField;
+ using pointer = value_type;
+ using reference = value_type;
+ reference operator*() const {
+ struct PerfettoPbDecoder decoder;
+ decoder.read_ptr = read_ptr_;
+ decoder.end_ptr = end_ptr_;
+ struct PerfettoPbDecoderField field;
+ do {
+ field = PerfettoPbDecoderParseField(&decoder);
+ } while (field.status == PERFETTO_PB_DECODER_OK &&
+ skipper_.ShouldSkip(field));
+ return field;
+ }
+ Iterator& operator++() {
+ struct PerfettoPbDecoder decoder;
+ decoder.read_ptr = read_ptr_;
+ decoder.end_ptr = end_ptr_;
+ PerfettoPbDecoderSkipField(&decoder);
+ read_ptr_ = decoder.read_ptr;
+ AdvanceToFirstInterestingField();
+ return *this;
+ }
+ Iterator operator++(int) {
+ Iterator tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const Iterator& a, const Iterator& b) {
+ return a.read_ptr_ == b.read_ptr_;
+ }
+ friend bool operator!=(const Iterator& a, const Iterator& b) {
+ return a.read_ptr_ != b.read_ptr_;
+ }
+
+ private:
+ Iterator(const uint8_t* read_ptr, const uint8_t* end_ptr,
+ const FieldSkipper& skipper)
+ : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) {
+ AdvanceToFirstInterestingField();
+ }
+ void AdvanceToFirstInterestingField() {
+ struct PerfettoPbDecoder decoder;
+ decoder.read_ptr = read_ptr_;
+ decoder.end_ptr = end_ptr_;
+ struct PerfettoPbDecoderField field;
+ const uint8_t* prev_read_ptr;
+ do {
+ prev_read_ptr = decoder.read_ptr;
+ field = PerfettoPbDecoderParseField(&decoder);
+ } while (field.status == PERFETTO_PB_DECODER_OK &&
+ skipper_.ShouldSkip(field));
+ if (field.status == PERFETTO_PB_DECODER_OK) {
+ read_ptr_ = prev_read_ptr;
+ } else {
+ read_ptr_ = decoder.read_ptr;
+ }
+ }
+ friend class FieldViewBase<FieldSkipper>;
+ const uint8_t* read_ptr_;
+ const uint8_t* end_ptr_;
+ const FieldSkipper& skipper_;
+ };
+ using value_type = const PerfettoPbDecoderField;
+ using const_iterator = Iterator;
+ template <typename... Args>
+ explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args)
+ : begin_(begin), end_(end), s_(args...) {
+ }
+ template <typename... Args>
+ explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args)
+ : FieldViewBase(data.data(), data.data() + data.size(), args...) {
+ }
+ template <typename... Args>
+ explicit FieldViewBase(const struct PerfettoPbDecoderField& field,
+ Args... args)
+ : s_(args...) {
+ if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
+ abort();
+ }
+ begin_ = field.value.delimited.start;
+ end_ = begin_ + field.value.delimited.len;
+ }
+ Iterator begin() const {
+ return Iterator(begin_, end_, s_);
+ }
+ Iterator end() const {
+ return Iterator(end_, end_, s_);
+ }
+ PerfettoPbDecoderField front() const {
+ return *begin();
+ }
+
+ size_t size() const {
+ size_t count = 0;
+ for (auto field : *this) {
+ (void)field;
+ count++;
+ }
+ return count;
+ }
+
+ bool ok() const {
+ for (auto field : *this) {
+ if (field.status != PERFETTO_PB_DECODER_OK) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ const uint8_t* begin_;
+ const uint8_t* end_;
+ FieldSkipper s_;
+};
+
+// Pretty printer for gtest
+template <typename FieldSkipper>
+void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) {
+ std::ostream& os = *pos;
+ os << "{";
+ for (PerfettoPbDecoderField f : field_view) {
+ PrintTo(f, pos);
+ os << ", ";
+ }
+ os << "}";
+}
+
+class IdFieldSkipper {
+ public:
+ explicit IdFieldSkipper(uint32_t id) : id_(id) {
+ }
+ explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) {
+ }
+ bool ShouldSkip(const struct PerfettoPbDecoderField& field) const {
+ return field.id != id_;
+ }
+
+ private:
+ uint32_t id_;
+};
+
+class NoFieldSkipper {
+ public:
+ NoFieldSkipper() = default;
+ bool ShouldSkip(const struct PerfettoPbDecoderField&) const {
+ return false;
+ }
+};
+
+// View over all the fields of a contiguous serialized protobuf message.
+//
+// Examples:
+//
+// for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) {
+// //...
+// }
+// FieldView fields2(/*PerfettoPbDecoderField*/ nested_field);
+// FieldView fields3(/*std::vector<uint8_t>*/ data);
+// size_t num = fields1.size(); // The number of fields.
+// bool ok = fields1.ok(); // Checks that the message is not malformed.
+using FieldView = FieldViewBase<NoFieldSkipper>;
+
+// Like `FieldView`, but only considers fields with a specific id.
+//
+// Examples:
+//
+// IdFieldView fields(msg_begin, msg_end, id)
+using IdFieldView = FieldViewBase<IdFieldSkipper>;
+
+// Matches a PerfettoPbDecoderField with the specified id. Accepts another
+// matcher to match the contents of the field.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, PbField(900, VarIntField(5)));
+template <typename M>
+auto PbField(int32_t id, M m) {
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::id, id), m);
+}
+
+// Matches a PerfettoPbDecoderField submessage field. Accepts a container
+// matcher for the subfields.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, MsgField(ElementsAre(...)));
+template <typename M>
+auto MsgField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField length delimited field. Accepts a string
+// matcher.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, StringField("string"));
+template <typename M>
+auto StringField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return std::string(
+ reinterpret_cast<const char*>(field.value.delimited.start),
+ field.value.delimited.len);
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, VarIntField(1)));
+template <typename M>
+auto VarIntField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.integer64;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_VARINT),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField fixed64 field. Accepts an integer matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, Fixed64Field(1)));
+template <typename M>
+auto Fixed64Field(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.integer64;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED64),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField fixed32 field. Accepts an integer matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, Fixed32Field(1)));
+template <typename M>
+auto Fixed32Field(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.integer32;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED32),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField double field. Accepts a double matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, DoubleField(1.0)));
+template <typename M>
+auto DoubleField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.double_val;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED64),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField float field. Accepts a float matcher
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, FloatField(1.0)));
+template <typename M>
+auto FloatField(M m) {
+ auto f = [](const PerfettoPbDecoderField& field) {
+ return field.value.float_val;
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_FIXED32),
+ testing::ResultOf(f, m));
+}
+
+// Matches a PerfettoPbDecoderField submessage field. Accepts a container
+// matcher for the subfields.
+//
+// Example:
+// PerfettoPbDecoderField field = ...
+// EXPECT_THAT(field, AllFieldsWithId(900, ElementsAre(...)));
+template <typename M>
+auto AllFieldsWithId(int32_t id, M m) {
+ auto f = [id](const PerfettoPbDecoderField& field) {
+ return IdFieldView(field, id);
+ };
+ return testing::AllOf(
+ testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
+ testing::Field(&PerfettoPbDecoderField::wire_type,
+ PERFETTO_PB_WIRE_TYPE_DELIMITED),
+ testing::ResultOf(f, m));
+}
+
+} // namespace test_utils
+} // namespace shlib
+} // namespace perfetto
+
+#endif // UTILS_H
diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp
new file mode 100644
index 0000000..c7fb8bd
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_perfetto.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2024 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 "tracing_perfetto.h"
+
+#include <cutils/trace.h>
+
+#include "perfetto/public/te_category_macros.h"
+#include "trace_categories.h"
+#include "tracing_perfetto_internal.h"
+
+namespace tracing_perfetto {
+
+void registerWithPerfetto(bool test) {
+ internal::registerWithPerfetto(test);
+}
+
+Result traceBegin(uint64_t category, const char* name) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceBegin(*perfettoTeCategory, name);
+ } else {
+ atrace_begin(category, name);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceEnd(uint64_t category) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceEnd(*perfettoTeCategory);
+ } else {
+ atrace_end(category);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncBegin(*perfettoTeCategory, name, cookie);
+ } else {
+ atrace_async_begin(category, name, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncEnd(*perfettoTeCategory, name, cookie);
+ } else {
+ atrace_async_end(category, name, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncBeginForTrack(uint64_t category, const char* name,
+ const char* trackName, int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
+ } else {
+ atrace_async_for_track_begin(category, trackName, name, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
+ int32_t cookie) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
+ } else {
+ atrace_async_for_track_end(category, trackName, cookie);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceInstant(uint64_t category, const char* name) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceInstant(*perfettoTeCategory, name);
+ } else {
+ atrace_instant(category, name);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceInstantForTrack(uint64_t category, const char* trackName,
+ const char* name) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceInstantForTrack(*perfettoTeCategory, trackName, name);
+ } else {
+ atrace_instant_for_track(category, trackName, name);
+ return Result::SUCCESS;
+ }
+}
+
+Result traceCounter(uint64_t category, const char* name, int64_t value) {
+ struct PerfettoTeCategory* perfettoTeCategory =
+ internal::toPerfettoCategory(category);
+ if (perfettoTeCategory != nullptr) {
+ return internal::perfettoTraceCounter(*perfettoTeCategory, name, value);
+ } else {
+ atrace_int64(category, name, value);
+ return Result::SUCCESS;
+ }
+}
+
+uint64_t getEnabledCategories() {
+ if (internal::isPerfettoSdkTracingEnabled()) {
+ return internal::getDefaultCategories();
+ } else {
+ return atrace_get_enabled_tags();
+ }
+}
+
+} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
new file mode 100644
index 0000000..58ba428
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#define FRAMEWORK_CATEGORIES(C) \
+ C(always, "always", "Always category") \
+ C(graphics, "graphics", "Graphics category") \
+ C(input, "input", "Input category") \
+ C(view, "view", "View category") \
+ C(webview, "webview", "WebView category") \
+ C(windowmanager, "wm", "WindowManager category") \
+ C(activitymanager, "am", "ActivityManager category") \
+ C(syncmanager, "syncmanager", "SyncManager category") \
+ C(audio, "audio", "Audio category") \
+ C(video, "video", "Video category") \
+ C(camera, "camera", "Camera category") \
+ C(hal, "hal", "HAL category") \
+ C(app, "app", "App category") \
+ C(resources, "res", "Resources category") \
+ C(dalvik, "dalvik", "Dalvik category") \
+ C(rs, "rs", "RS category") \
+ C(bionic, "bionic", "Bionic category") \
+ C(power, "power", "Power category") \
+ C(packagemanager, "packagemanager", "PackageManager category") \
+ C(systemserver, "ss", "System Server category") \
+ C(database, "database", "Database category") \
+ C(network, "network", "Network category") \
+ C(adb, "adb", "ADB category") \
+ C(vibrator, "vibrator", "Vibrator category") \
+ C(aidl, "aidl", "AIDL category") \
+ C(nnapi, "nnapi", "NNAPI category") \
+ C(rro, "rro", "RRO category") \
+ C(thermal, "thermal", "Thermal category")
+
+#include "tracing_perfetto_internal.h"
+
+#include <inttypes.h>
+
+#include <mutex>
+
+#include <android_os.h>
+
+#include "perfetto/public/compiler.h"
+#include "perfetto/public/producer.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+#include "trace_categories.h"
+#include "trace_result.h"
+
+namespace tracing_perfetto {
+
+namespace internal {
+
+namespace {
+
+PERFETTO_TE_CATEGORIES_DECLARE(FRAMEWORK_CATEGORIES);
+
+PERFETTO_TE_CATEGORIES_DEFINE(FRAMEWORK_CATEGORIES);
+
+struct PerfettoTeCategory* toCategory(uint64_t inCategory) {
+ switch (inCategory) {
+ case TRACE_CATEGORY_ALWAYS:
+ return &always;
+ case TRACE_CATEGORY_GRAPHICS:
+ return &graphics;
+ case TRACE_CATEGORY_INPUT:
+ return &input;
+ case TRACE_CATEGORY_VIEW:
+ return &view;
+ case TRACE_CATEGORY_WEBVIEW:
+ return &webview;
+ case TRACE_CATEGORY_WINDOW_MANAGER:
+ return &windowmanager;
+ case TRACE_CATEGORY_ACTIVITY_MANAGER:
+ return &activitymanager;
+ case TRACE_CATEGORY_SYNC_MANAGER:
+ return &syncmanager;
+ case TRACE_CATEGORY_AUDIO:
+ return &audio;
+ case TRACE_CATEGORY_VIDEO:
+ return &video;
+ case TRACE_CATEGORY_CAMERA:
+ return &camera;
+ case TRACE_CATEGORY_HAL:
+ return &hal;
+ case TRACE_CATEGORY_APP:
+ return &app;
+ case TRACE_CATEGORY_RESOURCES:
+ return &resources;
+ case TRACE_CATEGORY_DALVIK:
+ return &dalvik;
+ case TRACE_CATEGORY_RS:
+ return &rs;
+ case TRACE_CATEGORY_BIONIC:
+ return &bionic;
+ case TRACE_CATEGORY_POWER:
+ return &power;
+ case TRACE_CATEGORY_PACKAGE_MANAGER:
+ return &packagemanager;
+ case TRACE_CATEGORY_SYSTEM_SERVER:
+ return &systemserver;
+ case TRACE_CATEGORY_DATABASE:
+ return &database;
+ case TRACE_CATEGORY_NETWORK:
+ return &network;
+ case TRACE_CATEGORY_ADB:
+ return &adb;
+ case TRACE_CATEGORY_VIBRATOR:
+ return &vibrator;
+ case TRACE_CATEGORY_AIDL:
+ return &aidl;
+ case TRACE_CATEGORY_NNAPI:
+ return &nnapi;
+ case TRACE_CATEGORY_RRO:
+ return &rro;
+ case TRACE_CATEGORY_THERMAL:
+ return &thermal;
+ default:
+ return nullptr;
+ }
+}
+
+} // namespace
+
+bool isPerfettoSdkTracingEnabled() {
+ return android::os::perfetto_sdk_tracing();
+}
+
+struct PerfettoTeCategory* toPerfettoCategory(uint64_t category) {
+ if (!isPerfettoSdkTracingEnabled()) {
+ return nullptr;
+ }
+
+ struct PerfettoTeCategory* perfettoCategory = toCategory(category);
+ bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
+ (*perfettoCategory).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+ return enabled ? perfettoCategory : nullptr;
+}
+
+void registerWithPerfetto(bool test) {
+ if (!isPerfettoSdkTracingEnabled()) {
+ return;
+ }
+ static std::once_flag registration;
+ std::call_once(registration, [test]() {
+ struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT();
+ args.backends = test ? PERFETTO_BACKEND_IN_PROCESS : PERFETTO_BACKEND_SYSTEM;
+ PerfettoProducerInit(args);
+ PerfettoTeInit();
+ PERFETTO_TE_REGISTER_CATEGORIES(FRAMEWORK_CATEGORIES);
+ });
+}
+
+Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name) {
+ PERFETTO_TE(category, PERFETTO_TE_SLICE_BEGIN(name));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceEnd(const struct PerfettoTeCategory& category) {
+ PERFETTO_TE(category, PERFETTO_TE_SLICE_END());
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+ const char* trackName, uint64_t cookie) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_SLICE_BEGIN(name),
+ PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, uint64_t cookie) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_SLICE_END(),
+ PERFETTO_TE_NAMED_TRACK(trackName, cookie, PerfettoTeProcessTrackUuid()));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie) {
+ return perfettoTraceAsyncBeginForTrack(category, name, name, cookie);
+}
+
+Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie) {
+ return perfettoTraceAsyncEndForTrack(category, name, cookie);
+}
+
+Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name) {
+ PERFETTO_TE(category, PERFETTO_TE_INSTANT(name));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, const char* name) {
+ PERFETTO_TE(
+ category, PERFETTO_TE_INSTANT(name),
+ PERFETTO_TE_NAMED_TRACK(trackName, 1, PerfettoTeProcessTrackUuid()));
+ return Result::SUCCESS;
+}
+
+Result perfettoTraceCounter(const struct PerfettoTeCategory& category,
+ [[maybe_unused]] const char* name, int64_t value) {
+ PERFETTO_TE(category, PERFETTO_TE_COUNTER(),
+ PERFETTO_TE_INT_COUNTER(value));
+ return Result::SUCCESS;
+}
+
+uint64_t getDefaultCategories() {
+ return TRACE_CATEGORIES;
+}
+
+} // namespace internal
+
+} // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.h b/libs/tracing_perfetto/tracing_perfetto_internal.h
new file mode 100644
index 0000000..9a579f1
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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 TRACING_PERFETTO_INTERNAL_H
+#define TRACING_PERFETTO_INTERNAL_H
+
+#include <stdint.h>
+
+#include "include/trace_result.h"
+#include "perfetto/public/te_category_macros.h"
+
+namespace tracing_perfetto {
+
+namespace internal {
+
+bool isPerfettoSdkTracingEnabled();
+
+struct PerfettoTeCategory* toPerfettoCategory(uint64_t category);
+
+void registerWithPerfetto(bool test = false);
+
+Result perfettoTraceBegin(const struct PerfettoTeCategory& category, const char* name);
+
+Result perfettoTraceEnd(const struct PerfettoTeCategory& category);
+
+Result perfettoTraceAsyncBegin(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie);
+
+Result perfettoTraceAsyncEnd(const struct PerfettoTeCategory& category, const char* name,
+ uint64_t cookie);
+
+Result perfettoTraceAsyncBeginForTrack(const struct PerfettoTeCategory& category, const char* name,
+ const char* trackName, uint64_t cookie);
+
+Result perfettoTraceAsyncEndForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, uint64_t cookie);
+
+Result perfettoTraceInstant(const struct PerfettoTeCategory& category, const char* name);
+
+Result perfettoTraceInstantForTrack(const struct PerfettoTeCategory& category,
+ const char* trackName, const char* name);
+
+Result perfettoTraceCounter(const struct PerfettoTeCategory& category, const char* name,
+ int64_t value);
+
+uint64_t getDefaultCategories();
+
+} // namespace internal
+
+} // namespace tracing_perfetto
+
+#endif // TRACING_PERFETTO_INTERNAL_H
diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h
index 83e6a60..9c73f03 100644
--- a/services/inputflinger/dispatcher/CancelationOptions.h
+++ b/services/inputflinger/dispatcher/CancelationOptions.h
@@ -16,6 +16,8 @@
#pragma once
+#include "trace/EventTrackerInterface.h"
+
#include <input/Input.h>
#include <bitset>
#include <optional>
@@ -51,7 +53,13 @@
// The specific pointers to cancel, or nullopt to cancel all pointer events
std::optional<std::bitset<MAX_POINTER_ID + 1>> pointerIds = std::nullopt;
- CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {}
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker;
+
+ explicit CancelationOptions(Mode mode, const char* reason,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker)
+ : mode(mode), reason(reason), traceTracker(traceTracker) {}
+ CancelationOptions(const CancelationOptions&) = delete;
+ CancelationOptions operator=(const CancelationOptions&) = delete;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 56b0c8f..16875df 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -862,6 +862,30 @@
}
}
+class ScopedSyntheticEventTracer {
+public:
+ ScopedSyntheticEventTracer(std::unique_ptr<trace::InputTracerInterface>& tracer)
+ : mTracer(tracer) {
+ if (mTracer) {
+ mEventTracker = mTracer->createTrackerForSyntheticEvent();
+ }
+ }
+
+ ~ScopedSyntheticEventTracer() {
+ if (mTracer) {
+ mTracer->eventProcessingComplete(*mEventTracker);
+ }
+ }
+
+ const std::unique_ptr<trace::EventTrackerInterface>& getTracker() const {
+ return mEventTracker;
+ }
+
+private:
+ std::unique_ptr<trace::InputTracerInterface>& mTracer;
+ std::unique_ptr<trace::EventTrackerInterface> mEventTracker;
+};
+
} // namespace
// --- InputDispatcher ---
@@ -1479,8 +1503,9 @@
switch (entry.type) {
case EventEntry::Type::KEY: {
- CancelationOptions options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS, reason);
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS, reason,
+ keyEntry.traceTracker);
options.displayId = keyEntry.displayId;
options.deviceId = keyEntry.deviceId;
synthesizeCancelationEventsForAllConnectionsLocked(options);
@@ -1489,13 +1514,14 @@
case EventEntry::Type::MOTION: {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
if (motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) {
- CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, reason);
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, reason,
+ motionEntry.traceTracker);
options.displayId = motionEntry.displayId;
options.deviceId = motionEntry.deviceId;
synthesizeCancelationEventsForAllConnectionsLocked(options);
} else {
CancelationOptions options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
- reason);
+ reason, motionEntry.traceTracker);
options.displayId = motionEntry.displayId;
options.deviceId = motionEntry.deviceId;
synthesizeCancelationEventsForAllConnectionsLocked(options);
@@ -1630,7 +1656,9 @@
resetKeyRepeatLocked();
}
- CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS, "device was reset");
+ ScopedSyntheticEventTracer traceContext(mTracer);
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS, "device was reset",
+ traceContext.getTracker());
options.deviceId = entry.deviceId;
synthesizeCancelationEventsForAllConnectionsLocked(options);
@@ -1785,7 +1813,7 @@
DropReason* dropReason, nsecs_t& nextWakeupTime) {
// Preprocessing.
if (!entry->dispatchInProgress) {
- if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN &&
+ if (!entry->syntheticRepeat && entry->action == AKEY_EVENT_ACTION_DOWN &&
(entry->policyFlags & POLICY_FLAG_TRUSTED) &&
(!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
if (mKeyRepeatState.lastKeyEntry &&
@@ -2019,7 +2047,7 @@
CancelationOptions::Mode mode(
isPointerEvent ? CancelationOptions::Mode::CANCEL_POINTER_EVENTS
: CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS);
- CancelationOptions options(mode, "input event injection failed");
+ CancelationOptions options(mode, "input event injection failed", entry->traceTracker);
options.displayId = entry->displayId;
synthesizeCancelationEventsForMonitorsLocked(options);
return true;
@@ -2125,8 +2153,9 @@
if (connection->status != Connection::Status::NORMAL) {
return;
}
+ ScopedSyntheticEventTracer traceContext(mTracer);
CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS,
- "application not responding");
+ "application not responding", traceContext.getTracker());
sp<WindowInfoHandle> windowHandle;
if (!connection->monitor) {
@@ -3521,6 +3550,10 @@
LOG(INFO) << "Canceling pointers for device " << resolvedMotion->deviceId << " in "
<< connection->getInputChannelName() << " with event "
<< cancelEvent->getDescription();
+ if (mTracer) {
+ static_cast<MotionEntry&>(*cancelEvent).traceTracker =
+ mTracer->traceDerivedEvent(*cancelEvent, *resolvedMotion->traceTracker);
+ }
std::unique_ptr<DispatchEntry> cancelDispatchEntry =
createDispatchEntry(mIdGenerator, inputTarget, std::move(cancelEvent),
ftl::Flags<InputTarget::Flags>(), mWindowInfosVsyncId,
@@ -3758,7 +3791,8 @@
keyEntry.metaState, keyEntry.repeatCount,
keyEntry.downTime, keyEntry.eventTime);
if (mTracer) {
- mTracer->traceEventDispatch(*dispatchEntry, keyEntry.traceTracker.get());
+ ensureEventTraced(keyEntry);
+ mTracer->traceEventDispatch(*dispatchEntry, *keyEntry.traceTracker);
}
break;
}
@@ -3771,7 +3805,8 @@
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
status = publishMotionEvent(*connection, *dispatchEntry);
if (mTracer) {
- mTracer->traceEventDispatch(*dispatchEntry, motionEntry.traceTracker.get());
+ ensureEventTraced(motionEntry);
+ mTracer->traceEventDispatch(*dispatchEntry, *motionEntry.traceTracker);
}
break;
}
@@ -4150,6 +4185,11 @@
switch (cancelationEventEntry->type) {
case EventEntry::Type::KEY: {
+ if (mTracer) {
+ static_cast<KeyEntry&>(*cancelationEventEntry).traceTracker =
+ mTracer->traceDerivedEvent(*cancelationEventEntry,
+ *options.traceTracker);
+ }
const auto& keyEntry = static_cast<const KeyEntry&>(*cancelationEventEntry);
if (window) {
addWindowTargetLocked(window, InputTarget::DispatchMode::AS_IS,
@@ -4161,6 +4201,11 @@
break;
}
case EventEntry::Type::MOTION: {
+ if (mTracer) {
+ static_cast<MotionEntry&>(*cancelationEventEntry).traceTracker =
+ mTracer->traceDerivedEvent(*cancelationEventEntry,
+ *options.traceTracker);
+ }
const auto& motionEntry = static_cast<const MotionEntry&>(*cancelationEventEntry);
if (window) {
std::bitset<MAX_POINTER_ID + 1> pointerIds;
@@ -4208,6 +4253,9 @@
}
if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created";
+ if (mTracer) {
+ mTracer->dispatchToTargetHint(*options.traceTracker, targets[0]);
+ }
enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), targets[0]);
}
@@ -4219,7 +4267,8 @@
void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
const nsecs_t downTime, const std::shared_ptr<Connection>& connection,
- ftl::Flags<InputTarget::Flags> targetFlags) {
+ ftl::Flags<InputTarget::Flags> targetFlags,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) {
if (connection->status != Connection::Status::NORMAL) {
return;
}
@@ -4248,6 +4297,10 @@
std::vector<InputTarget> targets{};
switch (downEventEntry->type) {
case EventEntry::Type::MOTION: {
+ if (mTracer) {
+ static_cast<MotionEntry&>(*downEventEntry).traceTracker =
+ mTracer->traceDerivedEvent(*downEventEntry, *traceTracker);
+ }
const auto& motionEntry = static_cast<const MotionEntry&>(*downEventEntry);
if (windowHandle != nullptr) {
std::bitset<MAX_POINTER_ID + 1> pointerIds;
@@ -4285,6 +4338,9 @@
}
if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created";
+ if (mTracer) {
+ mTracer->dispatchToTargetHint(*traceTracker, targets[0]);
+ }
enqueueDispatchEntryLocked(connection, std::move(downEventEntry), targets[0]);
}
@@ -5222,6 +5278,7 @@
}
LOG(INFO) << "setInputWindows displayId=" << displayId << " " << windowList;
}
+ ScopedSyntheticEventTracer traceContext(mTracer);
// Check preconditions for new input windows
for (const sp<WindowInfoHandle>& window : windowInfoHandles) {
@@ -5261,7 +5318,7 @@
std::optional<FocusResolver::FocusChanges> changes =
mFocusResolver.setInputWindows(displayId, windowHandles);
if (changes) {
- onFocusChangedLocked(*changes, removedFocusedWindowHandle);
+ onFocusChangedLocked(*changes, traceContext.getTracker(), removedFocusedWindowHandle);
}
std::unordered_map<int32_t, TouchState>::iterator stateIt =
@@ -5274,7 +5331,7 @@
LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName()
<< " in display %" << displayId;
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
- "touched window was removed");
+ "touched window was removed", traceContext.getTracker());
synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
// Since we are about to drop the touch, cancel the events for the wallpaper as
// well.
@@ -5375,6 +5432,7 @@
}
{ // acquire lock
std::scoped_lock _l(mLock);
+ ScopedSyntheticEventTracer traceContext(mTracer);
if (mFocusedDisplayId != displayId) {
sp<IBinder> oldFocusedWindowToken =
@@ -5387,7 +5445,8 @@
}
CancelationOptions
options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
- "The display which contains this window no longer has focus.");
+ "The display which contains this window no longer has focus.",
+ traceContext.getTracker());
options.displayId = ADISPLAY_ID_NONE;
synthesizeCancelationEventsForWindowLocked(windowHandle, options);
}
@@ -5612,19 +5671,22 @@
}
// Synthesize cancel for old window and down for new window.
+ ScopedSyntheticEventTracer traceContext(mTracer);
std::shared_ptr<Connection> fromConnection = getConnectionLocked(fromToken);
std::shared_ptr<Connection> toConnection = getConnectionLocked(toToken);
if (fromConnection != nullptr && toConnection != nullptr) {
fromConnection->inputState.mergePointerStateTo(toConnection->inputState);
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
- "transferring touch from this window to another window");
+ "transferring touch from this window to another window",
+ traceContext.getTracker());
synthesizeCancelationEventsForWindowLocked(fromWindowHandle, options, fromConnection);
synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection,
- newTargetFlags);
+ newTargetFlags,
+ traceContext.getTracker());
// Check if the wallpaper window should deliver the corresponding event.
transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle,
- *state, deviceId, pointers);
+ *state, deviceId, pointers, traceContext.getTracker());
}
} // release lock
@@ -5692,7 +5754,9 @@
ALOGD("Resetting and dropping all events (%s).", reason);
}
- CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS, reason);
+ ScopedSyntheticEventTracer traceContext(mTracer);
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS, reason,
+ traceContext.getTracker());
synthesizeCancelationEventsForAllConnectionsLocked(options);
resetKeyRepeatLocked();
@@ -6087,12 +6151,13 @@
return BAD_VALUE;
}
+ ScopedSyntheticEventTracer traceContext(mTracer);
for (const DeviceId deviceId : deviceIds) {
TouchState& state = *statePtr;
TouchedWindow& window = *windowPtr;
// Send cancel events to all the input channels we're stealing from.
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
- "input channel stole pointer stream");
+ "input channel stole pointer stream", traceContext.getTracker());
options.deviceId = deviceId;
options.displayId = displayId;
std::vector<PointerProperties> pointers = window.getTouchingPointers(deviceId);
@@ -6516,7 +6581,8 @@
CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
"application handled the original non-fallback key "
"or is no longer a foreground target, "
- "canceling previously dispatched fallback key");
+ "canceling previously dispatched fallback key",
+ keyEntry.traceTracker);
options.keyCode = *fallbackKeyCode;
synthesizeCancelationEventsForWindowLocked(windowHandle, options, connection);
}
@@ -6598,7 +6664,8 @@
const auto windowHandle = getWindowHandleLocked(connection->getToken());
if (windowHandle != nullptr) {
CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
- "canceling fallback, policy no longer desires it");
+ "canceling fallback, policy no longer desires it",
+ keyEntry.traceTracker);
options.keyCode = *fallbackKeyCode;
synthesizeCancelationEventsForWindowLocked(windowHandle, options, connection);
}
@@ -6736,16 +6803,19 @@
std::scoped_lock _l(mLock);
std::optional<FocusResolver::FocusChanges> changes =
mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
+ ScopedSyntheticEventTracer traceContext(mTracer);
if (changes) {
- onFocusChangedLocked(*changes);
+ onFocusChangedLocked(*changes, traceContext.getTracker());
}
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
-void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes,
- const sp<WindowInfoHandle> removedFocusedWindowHandle) {
+void InputDispatcher::onFocusChangedLocked(
+ const FocusResolver::FocusChanges& changes,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker,
+ const sp<WindowInfoHandle> removedFocusedWindowHandle) {
if (changes.oldFocus) {
const auto resolvedWindow = removedFocusedWindowHandle != nullptr
? removedFocusedWindowHandle
@@ -6754,7 +6824,7 @@
LOG(FATAL) << __func__ << ": Previously focused token did not have a window";
}
CancelationOptions options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
- "focus left window");
+ "focus left window", traceTracker);
synthesizeCancelationEventsForWindowLocked(resolvedWindow, options);
enqueueFocusEventLocked(changes.oldFocus, /*hasFocus=*/false, changes.reason);
}
@@ -6907,9 +6977,10 @@
void InputDispatcher::cancelCurrentTouch() {
{
std::scoped_lock _l(mLock);
+ ScopedSyntheticEventTracer traceContext(mTracer);
ALOGD("Canceling all ongoing pointer gestures on all displays.");
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
- "cancel current touch");
+ "cancel current touch", traceContext.getTracker());
synthesizeCancelationEventsForAllConnectionsLocked(options);
mTouchStatesByDisplay.clear();
@@ -6959,12 +7030,12 @@
}
}
-void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
- ftl::Flags<InputTarget::Flags> newTargetFlags,
- const sp<WindowInfoHandle> fromWindowHandle,
- const sp<WindowInfoHandle> toWindowHandle,
- TouchState& state, int32_t deviceId,
- const std::vector<PointerProperties>& pointers) {
+void InputDispatcher::transferWallpaperTouch(
+ ftl::Flags<InputTarget::Flags> oldTargetFlags,
+ ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<WindowInfoHandle> fromWindowHandle,
+ const sp<WindowInfoHandle> toWindowHandle, TouchState& state, int32_t deviceId,
+ const std::vector<PointerProperties>& pointers,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) {
const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
fromWindowHandle->getInfo()->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
@@ -6982,7 +7053,7 @@
if (oldWallpaper != nullptr) {
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
- "transferring touch focus to another window");
+ "transferring touch focus to another window", traceTracker);
state.removeWindowByToken(oldWallpaper->getToken());
synthesizeCancelationEventsForWindowLocked(oldWallpaper, options);
}
@@ -7002,7 +7073,7 @@
getConnectionLocked(toWindowHandle->getToken());
toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState);
synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection,
- wallpaperFlags);
+ wallpaperFlags, traceTracker);
}
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 269bfdd..d6eba64 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -628,7 +628,8 @@
void synthesizePointerDownEventsForConnectionLocked(
const nsecs_t downTime, const std::shared_ptr<Connection>& connection,
- ftl::Flags<InputTarget::Flags> targetFlags) REQUIRES(mLock);
+ ftl::Flags<InputTarget::Flags> targetFlags,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) REQUIRES(mLock);
// Splitting motion events across windows. When splitting motion event for a target,
// splitDownTime refers to the time of first 'down' event on that particular target
@@ -657,6 +658,7 @@
void doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& focusedWindowToken,
const KeyEntry& entry) REQUIRES(mLock);
void onFocusChangedLocked(const FocusResolver::FocusChanges& changes,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker,
const sp<gui::WindowInfoHandle> removedFocusedWindowHandle = nullptr)
REQUIRES(mLock);
void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken)
@@ -704,7 +706,9 @@
const sp<android::gui::WindowInfoHandle> fromWindowHandle,
const sp<android::gui::WindowInfoHandle> toWindowHandle,
TouchState& state, int32_t deviceId,
- const std::vector<PointerProperties>& pointers) REQUIRES(mLock);
+ const std::vector<PointerProperties>& pointers,
+ const std::unique_ptr<trace::EventTrackerInterface>& traceTracker)
+ REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow(
const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/trace/InputTracer.cpp b/services/inputflinger/dispatcher/trace/InputTracer.cpp
index 3b5a096..83ed452 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.cpp
+++ b/services/inputflinger/dispatcher/trace/InputTracer.cpp
@@ -65,6 +65,10 @@
event);
}
+inline auto getId(const trace::TracedEvent& v) {
+ return std::visit([](const auto& event) { return event.id; }, v);
+}
+
} // namespace
// --- InputTracer ---
@@ -89,6 +93,12 @@
return std::make_unique<EventTrackerImpl>(std::move(eventState), /*isDerived=*/false);
}
+std::unique_ptr<EventTrackerInterface> InputTracer::createTrackerForSyntheticEvent() {
+ // Create a new EventState to track events derived from this tracker.
+ return std::make_unique<EventTrackerImpl>(std::make_shared<EventState>(*this),
+ /*isDerived=*/false);
+}
+
void InputTracer::dispatchToTargetHint(const EventTrackerInterface& cookie,
const InputTarget& target) {
if (isDerivedCookie(cookie)) {
@@ -111,11 +121,7 @@
LOG(FATAL) << "Traced event was already logged. "
"eventProcessingComplete() was likely called more than once.";
}
-
- for (const auto& event : eventState->events) {
- writeEventToBackend(event, *mBackend);
- }
- eventState->isEventProcessingComplete = true;
+ eventState->onEventProcessingComplete();
}
std::unique_ptr<EventTrackerInterface> InputTracer::traceDerivedEvent(
@@ -144,7 +150,8 @@
}
void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,
- const EventTrackerInterface* cookie) {
+ const EventTrackerInterface& cookie) {
+ auto& eventState = getState(cookie);
const EventEntry& entry = *dispatchEntry.eventEntry;
// TODO(b/328618922): Remove resolved key repeats after making repeatCount non-mutable.
// The KeyEntry's repeatCount is mutable and can be modified after an event is initially traced,
@@ -163,9 +170,13 @@
LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
}
- if (!cookie) {
- // This event was not tracked as an inbound event, so trace it now.
- writeEventToBackend(traced, *mBackend);
+ auto tracedEventIt =
+ std::find_if(eventState->events.begin(), eventState->events.end(),
+ [&traced](const auto& event) { return getId(traced) == getId(event); });
+ if (tracedEventIt == eventState->events.end()) {
+ LOG(FATAL)
+ << __func__
+ << ": Failed to find a previously traced event that matches the dispatched event";
}
// The vsyncId only has meaning if the event is targeting a window.
@@ -189,18 +200,24 @@
// --- InputTracer::EventState ---
+void InputTracer::EventState::onEventProcessingComplete() {
+ // Write all of the events known so far to the trace.
+ for (const auto& event : events) {
+ writeEventToBackend(event, *tracer.mBackend);
+ }
+ isEventProcessingComplete = true;
+}
+
InputTracer::EventState::~EventState() {
if (isEventProcessingComplete) {
// This event has already been written to the trace as expected.
return;
}
// The event processing was never marked as complete, so do it now.
- // TODO(b/210460522): Determine why/where the event is being destroyed before
- // eventProcessingComplete() is called.
- for (const auto& event : events) {
- writeEventToBackend(event, *tracer.mBackend);
- }
- isEventProcessingComplete = true;
+ // We should never end up here in normal operation. However, in tests, it's possible that we
+ // stop and destroy InputDispatcher without waiting for it to finish processing events, at
+ // which point an event (and thus its EventState) may be destroyed before processing finishes.
+ onEventProcessingComplete();
}
} // namespace android::inputdispatcher::trace::impl
diff --git a/services/inputflinger/dispatcher/trace/InputTracer.h b/services/inputflinger/dispatcher/trace/InputTracer.h
index ccff30e..529c0fa 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.h
+++ b/services/inputflinger/dispatcher/trace/InputTracer.h
@@ -42,11 +42,12 @@
InputTracer& operator=(const InputTracer&) = delete;
std::unique_ptr<EventTrackerInterface> traceInboundEvent(const EventEntry&) override;
+ std::unique_ptr<EventTrackerInterface> createTrackerForSyntheticEvent() override;
void dispatchToTargetHint(const EventTrackerInterface&, const InputTarget&) override;
void eventProcessingComplete(const EventTrackerInterface&) override;
std::unique_ptr<EventTrackerInterface> traceDerivedEvent(const EventEntry&,
const EventTrackerInterface&) override;
- void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface*) override;
+ void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface&) override;
private:
std::unique_ptr<InputTracingBackendInterface> mBackend;
@@ -56,6 +57,8 @@
explicit inline EventState(InputTracer& tracer) : tracer(tracer){};
~EventState();
+ void onEventProcessingComplete();
+
InputTracer& tracer;
std::vector<const TracedEvent> events;
bool isEventProcessingComplete{false};
diff --git a/services/inputflinger/dispatcher/trace/InputTracerInterface.h b/services/inputflinger/dispatcher/trace/InputTracerInterface.h
index daf716f..609d10c 100644
--- a/services/inputflinger/dispatcher/trace/InputTracerInterface.h
+++ b/services/inputflinger/dispatcher/trace/InputTracerInterface.h
@@ -52,6 +52,15 @@
* to track the event's lifecycle inside InputDispatcher.
*/
virtual std::unique_ptr<EventTrackerInterface> traceInboundEvent(const EventEntry&) = 0;
+
+ /**
+ * Create a trace tracker for a synthetic event that does not stem from an inbound input event.
+ * This includes things like generating cancellations or down events for various reasons,
+ * such as ANR, pilfering, transfer touch, etc. Any key or motion events generated for this
+ * synthetic event should be traced as a derived event using {@link #traceDerivedEvent}.
+ */
+ virtual std::unique_ptr<EventTrackerInterface> createTrackerForSyntheticEvent() = 0;
+
/**
* Notify the tracer that the traced event will be sent to the given InputTarget.
* The tracer may change how the event is logged depending on the target. For example,
@@ -89,11 +98,11 @@
/**
* Trace an input event being successfully dispatched to a window. The dispatched event may
- * be a previously traced inbound event, or it may be a synthesized event that has not been
- * previously traced. For inbound events that were previously traced, the EventTracker cookie
- * must be provided. For events that were not previously traced, the cookie must be null.
+ * be a previously traced inbound event, or it may be a synthesized event. All dispatched events
+ * must have been previously traced, so the trace tracker associated with the event must be
+ * provided.
*/
- virtual void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface*) = 0;
+ virtual void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface&) = 0;
};
} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f0f4d93..60d598f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -7477,6 +7477,12 @@
mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
/*expectedFlags=*/0);
}
+
+ void injectKeyRepeat(int32_t repeatCount) {
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, repeatCount, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ }
};
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
@@ -7565,6 +7571,17 @@
}
}
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_CorrectRepeatCountWhenInjectKeyRepeat) {
+ injectKeyRepeat(0);
+ mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ for (int32_t repeatCount = 1; repeatCount <= 2; ++repeatCount) {
+ expectKeyRepeatOnce(repeatCount);
+ }
+ injectKeyRepeat(1);
+ // Expect repeatCount to be 3 instead of 1
+ expectKeyRepeatOnce(3);
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
@@ -8709,9 +8726,10 @@
// Define a valid key down event that is stale (too old).
event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A,
- AMETA_NONE, /*repeatCount=*/1, eventTime, eventTime);
+ AMETA_NONE, /*repeatCount=*/0, eventTime, eventTime);
- const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+ const int32_t policyFlags =
+ POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
InputEventInjectionResult result =
mDispatcher->injectInputEvent(&event, /*targetUid=*/{},
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0638e02..dc69b81 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -210,7 +210,6 @@
"Scheduler/VsyncModulator.cpp",
"Scheduler/VsyncSchedule.cpp",
"ScreenCaptureOutput.cpp",
- "StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceFlingerDefaultFactory.cpp",
"Tracing/LayerDataSource.cpp",
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
deleted file mode 100644
index f42cd53..0000000
--- a/services/surfaceflinger/StartPropertySetThread.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-#include <cutils/properties.h>
-#include "StartPropertySetThread.h"
-
-namespace android {
-
-StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
- Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}
-
-status_t StartPropertySetThread::Start() {
- return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
-}
-
-bool StartPropertySetThread::threadLoop() {
- // Set property service.sf.present_timestamp, consumer need check its readiness
- property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
- // Clear BootAnimation exit flag
- property_set("service.bootanim.exit", "0");
- property_set("service.bootanim.progress", "0");
- // Start BootAnimation if not started
- property_set("ctl.start", "bootanim");
- // Exit immediately
- return false;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/StartPropertySetThread.h b/services/surfaceflinger/StartPropertySetThread.h
deleted file mode 100644
index bbdcde2..0000000
--- a/services/surfaceflinger/StartPropertySetThread.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 ANDROID_STARTBOOTANIMTHREAD_H
-#define ANDROID_STARTBOOTANIMTHREAD_H
-
-#include <stddef.h>
-
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
-
-namespace android {
-
-class StartPropertySetThread : public Thread {
-// Boot animation is triggered via calls to "property_set()" which can block
-// if init's executing slow operation such as 'mount_all --late' (currently
-// happening 1/10th with fsck) concurrently. Running in a separate thread
-// allows to pursue the SurfaceFlinger's init process without blocking.
-// see b/34499826.
-// Any property_set() will block during init stage so need to be offloaded
-// to this thread. see b/63844978.
-public:
- explicit StartPropertySetThread(bool timestampPropertyValue);
- status_t Start();
-private:
- virtual bool threadLoop();
- static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
- const bool mTimestampPropertyValue;
-};
-
-}
-
-#endif // ANDROID_STARTBOOTANIMTHREAD_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b3adedd..78e14ae 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -153,7 +153,6 @@
#include "Scheduler/VsyncConfiguration.h"
#include "Scheduler/VsyncModulator.h"
#include "ScreenCaptureOutput.h"
-#include "StartPropertySetThread.h"
#include "SurfaceFlingerProperties.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
@@ -566,7 +565,11 @@
initializeDisplays();
}));
- startBootAnim();
+ mInitBootPropsFuture.callOnce([this] {
+ return std::async(std::launch::async, &SurfaceFlinger::initBootProperties, this);
+ });
+
+ mInitBootPropsFuture.wait();
}
void SurfaceFlinger::run() {
@@ -722,13 +725,10 @@
}
mBootFinished = true;
FlagManager::getMutableInstance().markBootCompleted();
- if (mStartPropertySetThread->join() != NO_ERROR) {
- ALOGE("Join StartPropertySetThread failed!");
- }
- if (mRenderEnginePrimeCacheFuture.valid()) {
- mRenderEnginePrimeCacheFuture.get();
- }
+ mInitBootPropsFuture.wait();
+ mRenderEnginePrimeCacheFuture.wait();
+
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
@@ -816,8 +816,6 @@
}
}
-// Do not call property_set on main thread which will be blocked by init
-// Use StartPropertySetThread instead.
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
ATRACE_CALL();
ALOGI( "SurfaceFlinger's main thread ready to run. "
@@ -919,27 +917,40 @@
ALOGW("Can't set SCHED_OTHER for primeCache");
}
- bool shouldPrimeUltraHDR =
- base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false);
- mRenderEnginePrimeCacheFuture = getRenderEngine().primeCache(shouldPrimeUltraHDR);
+ mRenderEnginePrimeCacheFuture.callOnce([this] {
+ const bool shouldPrimeUltraHDR =
+ base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false);
+ return getRenderEngine().primeCache(shouldPrimeUltraHDR);
+ });
if (setSchedFifo(true) != NO_ERROR) {
ALOGW("Can't set SCHED_FIFO after primeCache");
}
}
- // Inform native graphics APIs whether the present timestamp is supported:
-
- mStartPropertySetThread = getFactory().createStartPropertySetThread(mHasReliablePresentFences);
-
- if (mStartPropertySetThread->Start() != NO_ERROR) {
- ALOGE("Run StartPropertySetThread failed!");
- }
+ // Avoid blocking the main thread on `init` to set properties.
+ mInitBootPropsFuture.callOnce([this] {
+ return std::async(std::launch::async, &SurfaceFlinger::initBootProperties, this);
+ });
initTransactionTraceWriter();
ALOGV("Done initializing");
}
+// During boot, offload `initBootProperties` to another thread. `property_set` depends on
+// `property_service`, which may be delayed by slow operations like `mount_all --late` in
+// the `init` process. See b/34499826 and b/63844978.
+void SurfaceFlinger::initBootProperties() {
+ property_set("service.sf.present_timestamp", mHasReliablePresentFences ? "1" : "0");
+
+ if (base::GetBoolProperty("debug.sf.boot_animation"s, true)) {
+ // Reset and (if needed) start BootAnimation.
+ property_set("service.bootanim.exit", "0");
+ property_set("service.bootanim.progress", "0");
+ property_set("ctl.start", "bootanim");
+ }
+}
+
void SurfaceFlinger::initTransactionTraceWriter() {
if (!mTransactionTracing) {
return;
@@ -979,18 +990,6 @@
static_cast<ui::ColorMode>(base::GetIntProperty("persist.sys.sf.color_mode"s, 0));
}
-void SurfaceFlinger::startBootAnim() {
- // Start boot animation service by setting a property mailbox
- // if property setting thread is already running, Start() will be just a NOP
- mStartPropertySetThread->Start();
- // Wait until property was set
- if (mStartPropertySetThread->join() != NO_ERROR) {
- ALOGE("Join StartPropertySetThread failed!");
- }
-}
-
-// ----------------------------------------------------------------------------
-
status_t SurfaceFlinger::getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const {
*outSupported = {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 005f2e6..0cc8fbb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -89,6 +89,7 @@
#include "Tracing/TransactionTracing.h"
#include "TransactionCallbackInvoker.h"
#include "TransactionState.h"
+#include "Utils/OnceFuture.h"
#include <atomic>
#include <cstdint>
@@ -550,7 +551,7 @@
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) override;
void bootFinished();
- virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const;
+ status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const;
sp<IDisplayEventConnection> createDisplayEventConnection(
gui::ISurfaceComposer::VsyncSource vsyncSource =
gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
@@ -871,9 +872,6 @@
// Traverse through all the layers and compute and cache its bounds.
void computeLayerBounds();
- // Boot animation, on/off animations and screen capture
- void startBootAnim();
-
bool layersHasProtectedLayer(const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const;
void captureScreenCommon(RenderAreaFuture, GetLayerSnapshotsFunction, ui::Size bufferSize,
@@ -1184,11 +1182,17 @@
ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const
REQUIRES(mStateLock);
void traverseLegacyLayers(const LayerVector::Visitor& visitor) const;
+
+ void initBootProperties();
void initTransactionTraceWriter();
- sp<StartPropertySetThread> mStartPropertySetThread;
+
surfaceflinger::Factory& mFactory;
pid_t mPid;
- std::future<void> mRenderEnginePrimeCacheFuture;
+
+ // TODO: b/328459745 - Encapsulate in a SystemProperties object.
+ utils::OnceFuture mInitBootPropsFuture;
+
+ utils::OnceFuture mRenderEnginePrimeCacheFuture;
// mStateLock has conventions related to the current thread, because only
// the main thread should modify variables protected by mStateLock.
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 7e6894d..50b167d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -26,7 +26,6 @@
#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
-#include "StartPropertySetThread.h"
#include "SurfaceFlingerDefaultFactory.h"
#include "SurfaceFlingerProperties.h"
@@ -53,11 +52,6 @@
}
}
-sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
- bool timestampPropertyValue) {
- return sp<StartPropertySetThread>::make(timestampPropertyValue);
-}
-
sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) {
return sp<DisplayDevice>::make(creationArgs);
}
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 2c6de0e..540dec8 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -29,7 +29,6 @@
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) override;
- sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index f310c4a..f1fbf01 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -39,7 +39,6 @@
class IGraphicBufferProducer;
class Layer;
class LayerFE;
-class StartPropertySetThread;
class SurfaceFlinger;
class TimeStats;
@@ -71,8 +70,6 @@
virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) = 0;
- virtual sp<StartPropertySetThread> createStartPropertySetThread(
- bool timestampPropertyValue) = 0;
virtual sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) = 0;
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
diff --git a/services/surfaceflinger/Utils/OnceFuture.h b/services/surfaceflinger/Utils/OnceFuture.h
new file mode 100644
index 0000000..412038c
--- /dev/null
+++ b/services/surfaceflinger/Utils/OnceFuture.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include <future>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
+
+namespace android::utils {
+
+// Allows a thread to `wait` for a future produced by a different thread. The future is returned by
+// the first call to a function `F` that multiple threads may `callOnce`. If no `callOnce` happens,
+// then `wait` does nothing. Otherwise, it blocks on the future, then destroys it, which resets the
+// `OnceFuture`.
+class OnceFuture {
+public:
+ template <typename F>
+ void callOnce(F f) {
+ std::lock_guard lock(mMutex);
+ if (!mFuture.valid()) {
+ mFuture = f();
+ }
+ }
+
+ void wait() {
+ std::lock_guard lock(mMutex);
+ if (mFuture.valid()) {
+ mFuture.wait();
+ mFuture = {};
+ }
+ }
+
+private:
+ std::mutex mMutex;
+ std::future<void> mFuture GUARDED_BY(mMutex);
+};
+
+} // namespace android::utils
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index bce7729..82023b0 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -43,7 +43,6 @@
#include "RenderArea.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/RefreshRateSelector.h"
-#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -94,10 +93,6 @@
return std::make_unique<scheduler::FakePhaseOffsets>();
}
- sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
- return sp<StartPropertySetThread>::make(timestampPropertyValue);
- }
-
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override {
return sp<DisplayDevice>::make(creationArgs);
}