blob: c442c8a1fd188034e935b228825d11848e4fb869 [file] [log] [blame]
Primiano Tucciec62e3e2019-07-26 22:18:31 +01001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "src/perfetto_cmd/perfetto_cmd.h"
18
19#include <inttypes.h>
20#include <sys/sendfile.h>
21
22#include "perfetto/base/build_config.h"
23#include "perfetto/base/logging.h"
Hector Dearman92d7d112019-12-05 15:19:57 +000024#include "perfetto/ext/base/uuid.h"
Primiano Tucciec62e3e2019-07-26 22:18:31 +010025#include "perfetto/tracing/core/trace_config.h"
Primiano Tucciec62e3e2019-07-26 22:18:31 +010026#include "src/android_internal/incident_service.h"
27#include "src/android_internal/lazy_library_loader.h"
Hector Dearman92d7d112019-12-05 15:19:57 +000028#include "src/android_internal/statsd_logging.h"
Primiano Tucciec62e3e2019-07-26 22:18:31 +010029
30namespace perfetto {
Hector Dearmand034e862020-08-03 15:50:52 +010031namespace {
32
33constexpr int64_t kSendfileTimeoutNs = 10UL * 1000 * 1000 * 1000; // 10s
34
35} // namespace
Primiano Tucciec62e3e2019-07-26 22:18:31 +010036
37void PerfettoCmd::SaveTraceIntoDropboxAndIncidentOrCrash() {
Hector Dearman62b60842020-09-16 11:46:16 +010038 PERFETTO_CHECK(is_uploading_);
39 PERFETTO_CHECK(
40 !trace_config_->incident_report_config().destination_package().empty());
Hector Dearman92d7d112019-12-05 15:19:57 +000041
42 if (bytes_written_ == 0) {
43 LogUploadEvent(PerfettoStatsdAtom::kNotUploadingEmptyTrace);
Hector Dearman62b60842020-09-16 11:46:16 +010044 PERFETTO_LOG("Skipping write to incident. Empty trace.");
Hector Dearman92d7d112019-12-05 15:19:57 +000045 return;
46 }
47
Hector Dearman62b60842020-09-16 11:46:16 +010048 // Save the trace as an incident.
49 SaveOutputToIncidentTraceOrCrash();
Primiano Tucciec62e3e2019-07-26 22:18:31 +010050
Hector Dearman62b60842020-09-16 11:46:16 +010051 // Ask incidentd to create a report, which will read the file we just
52 // wrote.
53 const auto& cfg = trace_config_->incident_report_config();
54 PERFETTO_LAZY_LOAD(android_internal::StartIncidentReport, incident_fn);
55 PERFETTO_CHECK(incident_fn(cfg.destination_package().c_str(),
56 cfg.destination_class().c_str(),
57 cfg.privacy_level()));
Primiano Tucciec62e3e2019-07-26 22:18:31 +010058}
59
60// Open a staging file (unlinking the previous instance), copy the trace
Ryan Savitski31cf1172019-08-01 16:13:20 +010061// contents over, then rename to a final hardcoded path (known to incidentd).
62// Such tracing sessions should not normally overlap. We do not use unique
63// unique filenames to avoid creating an unbounded amount of files in case of
64// errors.
Primiano Tucciec62e3e2019-07-26 22:18:31 +010065void PerfettoCmd::SaveOutputToIncidentTraceOrCrash() {
Hector Dearman92d7d112019-12-05 15:19:57 +000066 LogUploadEvent(PerfettoStatsdAtom::kUploadIncidentBegin);
Primiano Tucciec62e3e2019-07-26 22:18:31 +010067 char kIncidentTracePath[256];
68 sprintf(kIncidentTracePath, "%s/incident-trace", kStateDir);
69
70 char kTempIncidentTracePath[256];
71 sprintf(kTempIncidentTracePath, "%s.temp", kIncidentTracePath);
72
73 PERFETTO_CHECK(unlink(kTempIncidentTracePath) == 0 || errno == ENOENT);
74
Hector Dearmanab55ba82020-07-23 17:57:33 +010075 // TODO(b/155024256) These should not be necessary (we flush when destroying
76 // packet writer and sendfile should ignore file offset) however they should
77 // not harm anything and it will help debug the linked issue.
78 PERFETTO_CHECK(fflush(*trace_out_stream_) == 0);
79 PERFETTO_CHECK(fseek(*trace_out_stream_, 0, SEEK_SET) == 0);
80
Primiano Tucciec62e3e2019-07-26 22:18:31 +010081 // SELinux constrains the set of readers.
82 base::ScopedFile staging_fd =
Hector Dearmanab55ba82020-07-23 17:57:33 +010083 base::OpenFile(kTempIncidentTracePath, O_CREAT | O_EXCL | O_RDWR, 0666);
Primiano Tucciec62e3e2019-07-26 22:18:31 +010084 PERFETTO_CHECK(staging_fd);
Hector Dearmand034e862020-08-03 15:50:52 +010085
86 int fd = fileno(*trace_out_stream_);
Primiano Tucciec62e3e2019-07-26 22:18:31 +010087 off_t offset = 0;
Hector Dearmand034e862020-08-03 15:50:52 +010088 size_t remaining = static_cast<size_t>(bytes_written_);
89
Hector Dearmanc53d4da2020-10-01 12:35:16 +010090 // Count time in terms of CPU to avoid timeouts due to suspend:
91 base::TimeNanos start = base::GetThreadCPUTimeNs();
Hector Dearmand034e862020-08-03 15:50:52 +010092 for (;;) {
93 errno = 0;
94 PERFETTO_DCHECK(static_cast<size_t>(offset) + remaining == bytes_written_);
95 auto wsize = PERFETTO_EINTR(sendfile(*staging_fd, fd, &offset, remaining));
96 if (wsize < 0) {
97 PERFETTO_FATAL("sendfile() failed wsize=%zd, off=%" PRId64
98 ", initial=%" PRIu64 ", remaining=%zu",
99 wsize, static_cast<int64_t>(offset), bytes_written_,
100 remaining);
101 }
102 remaining -= static_cast<size_t>(wsize);
103 if (remaining == 0) {
104 break;
105 }
Hector Dearmanc53d4da2020-10-01 12:35:16 +0100106 base::TimeNanos now = base::GetThreadCPUTimeNs();
107 if (now < start || (now - start).count() > kSendfileTimeoutNs) {
Hector Dearmand034e862020-08-03 15:50:52 +0100108 PERFETTO_FATAL("sendfile() timed out wsize=%zd, off=%" PRId64
Hector Dearmanc53d4da2020-10-01 12:35:16 +0100109 ", initial=%" PRIu64
110 ", remaining=%zu, start=%lld, now=%lld",
Hector Dearmand034e862020-08-03 15:50:52 +0100111 wsize, static_cast<int64_t>(offset), bytes_written_,
Hector Dearmanc53d4da2020-10-01 12:35:16 +0100112 remaining, static_cast<long long int>(start.count()),
113 static_cast<long long int>(now.count()));
Hector Dearmand034e862020-08-03 15:50:52 +0100114 }
Hector Dearmanab55ba82020-07-23 17:57:33 +0100115 }
Hector Dearmand034e862020-08-03 15:50:52 +0100116
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100117 staging_fd.reset();
118 PERFETTO_CHECK(rename(kTempIncidentTracePath, kIncidentTracePath) == 0);
119 // Note: not calling fsync(2), as we're not interested in the file being
120 // consistent in case of a crash.
Hector Dearman92d7d112019-12-05 15:19:57 +0000121 LogUploadEvent(PerfettoStatsdAtom::kUploadIncidentSuccess);
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100122}
123
124// static
125base::ScopedFile PerfettoCmd::OpenDropboxTmpFile() {
126 // If we are tracing to DropBox, there's no need to make a
127 // filesystem-visible temporary file.
128 auto fd = base::OpenFile(kStateDir, O_TMPFILE | O_RDWR, 0600);
129 if (!fd)
130 PERFETTO_PLOG("Could not create a temporary trace file in %s", kStateDir);
131 return fd;
132}
133
Hector Dearman92d7d112019-12-05 15:19:57 +0000134void PerfettoCmd::LogUploadEventAndroid(PerfettoStatsdAtom atom) {
Hector Dearman62b60842020-09-16 11:46:16 +0100135 if (!is_uploading_)
Hector Dearman92d7d112019-12-05 15:19:57 +0000136 return;
137 PERFETTO_LAZY_LOAD(android_internal::StatsdLogEvent, log_event_fn);
138 base::Uuid uuid(uuid_);
139 log_event_fn(atom, uuid.lsb(), uuid.msb());
140}
141
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100142} // namespace perfetto