Pass trace fd directly to DropBox
Pass the trace file descriptor directly to DropBox in order to avoid
creating a temporary file in the filesystem (which we would have to
clean up in case of crashes).
Change-Id: I1a72c79c46b6283e276cf8be3cea639d5700f689
diff --git a/src/traced/perfetto_cmd/perfetto_cmd.cc b/src/traced/perfetto_cmd/perfetto_cmd.cc
index 5e90987..f3c236f 100644
--- a/src/traced/perfetto_cmd/perfetto_cmd.cc
+++ b/src/traced/perfetto_cmd/perfetto_cmd.cc
@@ -53,8 +53,19 @@
// from this process.
namespace perfetto {
namespace {
-const char kTempTraceDir[] = "/data/misc/perfetto-traces";
+
+// Temporary directory for DropBox traces. Note that this is automatically
+// created by the system by setting setprop persist.traced.enable=1.
+const char kTempDropBoxTraceDir[] = "/data/misc/perfetto-traces";
const char kDefaultDropBoxTag[] = "perfetto";
+
+std::string GetDirName(const std::string& path) {
+ size_t sep = path.find_last_of('/');
+ if (sep == std::string::npos)
+ return ".";
+ return path.substr(0, sep);
+}
+
} // namespace
using protozero::proto_utils::WriteVarInt;
@@ -79,8 +90,7 @@
void OnTraceData(std::vector<TracePacket>, bool has_more) override;
private:
- base::ScopedFile CreateTemporaryFile(std::string* out_path);
- void SaveTraceFileAs(const std::string& name);
+ bool OpenOutputFile();
PlatformTaskRunner task_runner_;
std::unique_ptr<perfetto::Service::ConsumerEndpoint> consumer_endpoint_;
@@ -191,17 +201,6 @@
return PrintUsage(argv[0]);
}
- if (access(kTempTraceDir, F_OK) == -1 && mkdir(kTempTraceDir, 0770) == -1) {
- PERFETTO_ELOG("Could not create temporary trace directory: %s",
- kTempTraceDir);
- return 1;
- }
-
- base::ScopedFile fd;
- fd = CreateTemporaryFile(&tmp_trace_out_path_);
- trace_out_stream_.reset(fdopen(fd.release(), "wb"));
- PERFETTO_CHECK(trace_out_stream_);
-
perfetto::protos::TraceConfig trace_config_proto;
PERFETTO_DLOG("Parsing TraceConfig, %zu bytes", trace_config_raw.size());
bool parsed = trace_config_proto.ParseFromString(trace_config_raw);
@@ -213,6 +212,9 @@
trace_config_->FromProto(trace_config_proto);
trace_config_raw.clear();
+ if (!OpenOutputFile())
+ return 1;
+
if (background) {
PERFETTO_CHECK(daemon(0 /*nochdir*/, 0 /*noclose*/) == 0);
PERFETTO_DLOG("Continuing in background");
@@ -275,21 +277,17 @@
consumer_endpoint_->FreeBuffers();
task_runner_.Quit();
- long bytes_written = ftell(trace_out_stream_.get());
+ fflush(*trace_out_stream_);
+ long bytes_written = ftell(*trace_out_stream_);
if (!dropbox_tag_.empty()) {
#if defined(PERFETTO_BUILD_WITH_ANDROID)
- // DropBox needs a path to the uploaded file, so make a temporarily visible
- // file.
- // TODO(skyostil): Modify DropBox to take an fd directly.
- std::string tmp_path;
- CreateTemporaryFile(&tmp_path);
- SaveTraceFileAs(tmp_path);
-
android::sp<android::os::DropBoxManager> dropbox =
new android::os::DropBoxManager();
+ fseek(*trace_out_stream_, 0, SEEK_SET);
+ // DropBox takes ownership of the file descriptor, so give it a duplicate.
+ base::ScopedFile fd(dup(fileno(*trace_out_stream_)));
android::binder::Status status = dropbox->addFile(
- android::String16(dropbox_tag_.c_str()), tmp_path, 0 /* flags */);
- unlink(tmp_path.c_str());
+ android::String16(dropbox_tag_.c_str()), fd.release(), 0 /* flags */);
if (!status.isOk()) {
PERFETTO_ELOG("DropBox upload failed: %s", status.toString8().c_str());
return;
@@ -298,22 +296,37 @@
dropbox_tag_.c_str());
#endif // defined(PERFETTO_BUILD_WITH_ANDROID)
} else {
- SaveTraceFileAs(trace_out_path_);
+ PERFETTO_CHECK(
+ rename(tmp_trace_out_path_.c_str(), trace_out_path_.c_str()) == 0);
PERFETTO_ILOG("Wrote %ld bytes into %s", bytes_written,
trace_out_path_.c_str());
}
+ trace_out_stream_.reset();
did_process_full_trace_ = true;
}
-base::ScopedFile PerfettoCmd::CreateTemporaryFile(std::string* out_path) {
- *out_path = std::string(kTempTraceDir) + "/perfetto-traceXXXXXX";
- return base::ScopedFile(mkstemp(&(*out_path)[0]));
-}
-
-void PerfettoCmd::SaveTraceFileAs(const std::string& name) {
- PERFETTO_DCHECK(trace_out_stream_);
- PERFETTO_CHECK(rename(tmp_trace_out_path_.c_str(), name.c_str()) == 0);
- trace_out_stream_.reset();
+bool PerfettoCmd::OpenOutputFile() {
+ base::ScopedFile fd;
+ if (!dropbox_tag_.empty()) {
+ // If we are tracing to DropBox, there's no need to make a
+ // filesystem-visible temporary file.
+ // TODO(skyostil): Fall back to mkstemp() + open() + unlink() for older
+ // devices.
+ fd.reset(open(kTempDropBoxTraceDir, O_TMPFILE | O_RDWR, 0600));
+ if (!fd) {
+ PERFETTO_ELOG("Could not create a temporary trace file in %s",
+ kTempDropBoxTraceDir);
+ return false;
+ }
+ } else {
+ // Otherwise create a temporary file in the directory where the final trace
+ // is going to be.
+ tmp_trace_out_path_ = GetDirName(trace_out_path_) + "/perfetto-traceXXXXXX";
+ fd.reset(mkstemp(&tmp_trace_out_path_[0]));
+ }
+ trace_out_stream_.reset(fdopen(fd.release(), "wb"));
+ PERFETTO_CHECK(trace_out_stream_);
+ return true;
}
int __attribute__((visibility("default")))