Add statsd logging to perfetto_cmd
Bug: 133135459
Change-Id: Ie1045d6a26804f650ac580f8ffc2e4a9ff054da6
diff --git a/src/android_internal/BUILD.gn b/src/android_internal/BUILD.gn
index 819532a..4306b16 100644
--- a/src/android_internal/BUILD.gn
+++ b/src/android_internal/BUILD.gn
@@ -26,6 +26,7 @@
source_set("headers") {
deps = [
"../../gn:default_deps",
+ "../../src/perfetto_cmd:perfetto_atoms",
]
sources = [
"atrace_hal.h",
@@ -33,6 +34,7 @@
"health_hal.h",
"incident_service.h",
"power_stats_hal.h",
+ "statsd_logging.h",
]
}
@@ -66,11 +68,15 @@
"health_hal.cc",
"incident_service.cc",
"power_stats_hal.cc",
+ "statsd_logging.cc",
]
libs = [
"android.hardware.health@2.0",
"android.hardware.power.stats@1.0",
"android.hardware.atrace@1.0",
+ "statslog_perfetto",
+ "statssocket",
+ "cutils",
"base",
"binder",
"log",
diff --git a/src/android_internal/statsd_logging.cc b/src/android_internal/statsd_logging.cc
new file mode 100644
index 0000000..7c57e6b
--- /dev/null
+++ b/src/android_internal/statsd_logging.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/android_internal/statsd_logging.h"
+
+#include <string.h>
+
+#include <statslog_perfetto.h>
+
+namespace perfetto {
+namespace android_internal {
+
+void StatsdLogEvent(PerfettoStatsdAtom atom, const char* uuid) {
+ uint64_t uuid_lsb = 0;
+ uint64_t uuid_msb = 0;
+ memcpy(&uuid_lsb, uuid, 8);
+ memcpy(&uuid_msb, uuid + 8, 8);
+ stats_write(PERFETTO_UPLOADED, static_cast<int32_t>(atom), uuid_lsb,
+ uuid_msb);
+}
+
+} // namespace android_internal
+} // namespace perfetto
diff --git a/src/android_internal/statsd_logging.h b/src/android_internal/statsd_logging.h
new file mode 100644
index 0000000..9590ab6
--- /dev/null
+++ b/src/android_internal/statsd_logging.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_ANDROID_INTERNAL_STATSD_LOGGING_H_
+#define SRC_ANDROID_INTERNAL_STATSD_LOGGING_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "src/perfetto_cmd/perfetto_atoms.h"
+
+namespace perfetto {
+namespace android_internal {
+
+extern "C" {
+
+void __attribute__((visibility("default")))
+StatsdLogEvent(PerfettoStatsdAtom atom, const char* uuid);
+
+} // extern "C"
+
+} // namespace android_internal
+} // namespace perfetto
+
+#endif // SRC_ANDROID_INTERNAL_STATSD_LOGGING_H_
diff --git a/src/perfetto_cmd/BUILD.gn b/src/perfetto_cmd/BUILD.gn
index fe6cf12..38a3e53 100644
--- a/src/perfetto_cmd/BUILD.gn
+++ b/src/perfetto_cmd/BUILD.gn
@@ -44,6 +44,12 @@
]
}
+source_set("perfetto_atoms") {
+ sources = [
+ "perfetto_atoms.h",
+ ]
+}
+
# Contains all the implementation but not the main() entry point. This target
# is shared both by the executable and tests.
source_set("perfetto_cmd") {
@@ -52,6 +58,7 @@
"../../include/perfetto/ext/traced",
]
deps = [
+ ":perfetto_atoms",
":trigger_producer",
"../../gn:default_deps",
"../../gn:zlib",
diff --git a/src/perfetto_cmd/perfetto_atoms.h b/src/perfetto_cmd/perfetto_atoms.h
new file mode 100644
index 0000000..35903ea
--- /dev/null
+++ b/src/perfetto_cmd/perfetto_atoms.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_PERFETTO_CMD_PERFETTO_ATOMS_H_
+#define SRC_PERFETTO_CMD_PERFETTO_ATOMS_H_
+
+namespace perfetto {
+
+// This must match the values of the PerfettoUploadEvent enum in:
+// frameworks/base/cmds/statsd/src/atoms.proto
+enum class PerfettoStatsdAtom {
+ kUndefined = 0,
+
+ kTraceBegin = 1,
+ kBackgroundTraceBegin = 2,
+
+ kOnConnect = 3,
+ kOnTracingDisabled = 4,
+
+ kUploadDropboxBegin = 5,
+ kUploadDropboxSuccess = 6,
+ kUploadDropboxFailure = 7,
+
+ kUploadIncidentBegin = 8,
+ kUploadIncidentSuccess = 9,
+ kUploadIncidentFailure = 10,
+
+ kFinalizeTraceAndExit = 11,
+
+ kTriggerBegin = 12,
+ kTriggerSuccess = 13,
+ kTriggerFailure = 14,
+
+ kHitGuardrails = 15,
+ kOnTimeout = 16,
+ kNotUploadingEmptyTrace = 17,
+};
+
+} // namespace perfetto
+
+#endif // SRC_PERFETTO_CMD_PERFETTO_ATOMS_H_
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index da3850b..3727a7f 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -30,11 +30,13 @@
#include <iterator>
#include <sstream>
+#include "perfetto/base/compiler.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/string_view.h"
#include "perfetto/ext/base/utils.h"
+#include "perfetto/ext/base/uuid.h"
#include "perfetto/ext/traced/traced.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/trace_packet.h"
@@ -545,6 +547,7 @@
// connect as a consumer or run the trace. So bail out after processing all
// the options.
if (!triggers_to_activate.empty()) {
+ LogUploadEvent(PerfettoStatsdAtom::kTriggerBegin);
bool finished_with_success = false;
TriggerProducer producer(
&task_runner_,
@@ -554,6 +557,11 @@
},
&triggers_to_activate);
task_runner_.Run();
+ if (finished_with_success) {
+ LogUploadEvent(PerfettoStatsdAtom::kTriggerSuccess);
+ } else {
+ LogUploadEvent(PerfettoStatsdAtom::kTriggerFailure);
+ }
return finished_with_success ? 0 : 1;
}
@@ -601,8 +609,16 @@
expected_duration_ms_ = timeout_ms + max_stop_delay_ms;
}
- if (!limiter.ShouldTrace(args))
+ if (trace_config_->trigger_config().trigger_timeout_ms() == 0) {
+ LogUploadEvent(PerfettoStatsdAtom::kTraceBegin);
+ } else {
+ LogUploadEvent(PerfettoStatsdAtom::kBackgroundTraceBegin);
+ }
+
+ if (!limiter.ShouldTrace(args)) {
+ LogUploadEvent(PerfettoStatsdAtom::kHitGuardrails);
return 1;
+ }
consumer_endpoint_ =
ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_);
@@ -614,6 +630,7 @@
}
void PerfettoCmd::OnConnect() {
+ LogUploadEvent(PerfettoStatsdAtom::kOnConnect);
if (query_service_) {
consumer_endpoint_->QueryServiceState(
[this](bool success, const TracingServiceState& svc_state) {
@@ -666,6 +683,7 @@
void PerfettoCmd::OnTimeout() {
PERFETTO_ELOG("Timed out while waiting for trace from the service, aborting");
+ LogUploadEvent(PerfettoStatsdAtom::kOnTimeout);
task_runner_.Quit();
}
@@ -693,6 +711,8 @@
}
void PerfettoCmd::OnTracingDisabled() {
+ LogUploadEvent(PerfettoStatsdAtom::kOnTracingDisabled);
+
if (trace_config_->write_into_file()) {
// If write_into_file == true, at this point the passed file contains
// already all the packets.
@@ -708,6 +728,7 @@
}
void PerfettoCmd::FinalizeTraceAndExit() {
+ LogUploadEvent(PerfettoStatsdAtom::kFinalizeTraceAndExit);
packet_writer_.reset();
if (trace_out_stream_) {
@@ -869,6 +890,14 @@
void PerfettoCmd::OnObservableEvents(
const ObservableEvents& /*observable_events*/) {}
+void PerfettoCmd::LogUploadEvent(PerfettoStatsdAtom atom) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ LogUploadEventAndroid(atom);
+#else
+ base::ignore_result(atom);
+#endif
+}
+
int __attribute__((visibility("default")))
PerfettoCmdMain(int argc, char** argv) {
g_consumer_cmd = new perfetto::PerfettoCmd();
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index ea93a8c..d09a120 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -28,12 +28,11 @@
#include "perfetto/ext/base/optional.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/unix_task_runner.h"
-#include "perfetto/ext/base/uuid.h"
#include "perfetto/ext/tracing/core/consumer.h"
#include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
-#include "src/perfetto_cmd/rate_limiter.h"
-
+#include "src/perfetto_cmd/perfetto_atoms.h"
#include "src/perfetto_cmd/perfetto_cmd_state.pb.h"
+#include "src/perfetto_cmd/rate_limiter.h"
namespace perfetto {
@@ -82,7 +81,9 @@
void SaveTraceIntoDropboxAndIncidentOrCrash();
void SaveOutputToDropboxOrCrash();
void SaveOutputToIncidentTraceOrCrash();
+ void LogUploadEventAndroid(PerfettoStatsdAtom atom);
#endif
+ void LogUploadEvent(PerfettoStatsdAtom atom);
base::UnixTaskRunner task_runner_;
diff --git a/src/perfetto_cmd/perfetto_cmd_android.cc b/src/perfetto_cmd/perfetto_cmd_android.cc
index ee131d9..46cff98 100644
--- a/src/perfetto_cmd/perfetto_cmd_android.cc
+++ b/src/perfetto_cmd/perfetto_cmd_android.cc
@@ -25,42 +25,50 @@
#include "src/android_internal/dropbox_service.h"
#include "src/android_internal/incident_service.h"
#include "src/android_internal/lazy_library_loader.h"
+#include "src/android_internal/statsd_logging.h"
namespace perfetto {
void PerfettoCmd::SaveTraceIntoDropboxAndIncidentOrCrash() {
PERFETTO_CHECK(!dropbox_tag_.empty());
+ bool use_dropbox = !trace_config_->incident_report_config().skip_dropbox();
+ bool use_incident =
+ !trace_config_->incident_report_config().destination_package().empty();
+
+ if (bytes_written_ == 0) {
+ LogUploadEvent(PerfettoStatsdAtom::kNotUploadingEmptyTrace);
+ if (use_dropbox)
+ PERFETTO_LOG("Skipping write to dropbox. Empty trace.");
+ if (use_incident)
+ PERFETTO_LOG("Skipping write to incident. Empty trace.");
+ return;
+ }
+
// Otherwise, write to Dropbox unless there's a special override in the
// incident report config.
- if (!trace_config_->incident_report_config().skip_dropbox()) {
- if (bytes_written_ == 0) {
- PERFETTO_LOG("Skipping write to dropbox. Empty trace.");
- } else {
- SaveOutputToDropboxOrCrash();
- }
+ if (use_dropbox) {
+ SaveOutputToDropboxOrCrash();
}
// Optionally save the trace as an incident. This is either in addition to, or
// instead of, the Dropbox write.
- if (!trace_config_->incident_report_config().destination_package().empty()) {
- if (bytes_written_ == 0) {
- PERFETTO_LOG("Skipping incident report. Empty trace.");
- } else {
- SaveOutputToIncidentTraceOrCrash();
+ if (use_incident) {
+ SaveOutputToIncidentTraceOrCrash();
- // Ask incidentd to create a report, which will read the file we just
- // wrote.
- const auto& cfg = trace_config_->incident_report_config();
- PERFETTO_LAZY_LOAD(android_internal::StartIncidentReport, incident_fn);
- PERFETTO_CHECK(incident_fn(cfg.destination_package().c_str(),
- cfg.destination_class().c_str(),
- cfg.privacy_level()));
- }
+ // Ask incidentd to create a report, which will read the file we just
+ // wrote.
+ const auto& cfg = trace_config_->incident_report_config();
+ PERFETTO_LAZY_LOAD(android_internal::StartIncidentReport, incident_fn);
+ PERFETTO_CHECK(incident_fn(cfg.destination_package().c_str(),
+ cfg.destination_class().c_str(),
+ cfg.privacy_level()));
}
}
void PerfettoCmd::SaveOutputToDropboxOrCrash() {
+ LogUploadEvent(PerfettoStatsdAtom::kUploadDropboxBegin);
+
PERFETTO_CHECK(fseek(*trace_out_stream_, 0, SEEK_SET) == 0);
// DropBox takes ownership of the file descriptor, so give it a duplicate.
@@ -73,10 +81,12 @@
PERFETTO_LAZY_LOAD(android_internal::SaveIntoDropbox, dropbox_fn);
if (dropbox_fn(dropbox_tag_.c_str(), read_only_fd.release())) {
+ LogUploadEvent(PerfettoStatsdAtom::kUploadDropboxSuccess);
PERFETTO_LOG("Wrote %" PRIu64
" bytes (before compression) into DropBox with tag %s",
bytes_written_, dropbox_tag_.c_str());
} else {
+ LogUploadEvent(PerfettoStatsdAtom::kUploadDropboxFailure);
PERFETTO_FATAL("DropBox upload failed");
}
}
@@ -87,6 +97,7 @@
// unique filenames to avoid creating an unbounded amount of files in case of
// errors.
void PerfettoCmd::SaveOutputToIncidentTraceOrCrash() {
+ LogUploadEvent(PerfettoStatsdAtom::kUploadIncidentBegin);
char kIncidentTracePath[256];
sprintf(kIncidentTracePath, "%s/incident-trace", kStateDir);
@@ -107,6 +118,7 @@
PERFETTO_CHECK(rename(kTempIncidentTracePath, kIncidentTracePath) == 0);
// Note: not calling fsync(2), as we're not interested in the file being
// consistent in case of a crash.
+ LogUploadEvent(PerfettoStatsdAtom::kUploadIncidentSuccess);
}
// static
@@ -119,4 +131,11 @@
return fd;
}
+void PerfettoCmd::LogUploadEventAndroid(PerfettoStatsdAtom atom) {
+ if (dropbox_tag_.empty())
+ return;
+ PERFETTO_LAZY_LOAD(android_internal::StatsdLogEvent, log_event_fn);
+ log_event_fn(atom, uuid_.c_str());
+}
+
} // namespace perfetto