Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3376)

Unified Diff: chrome/browser/chromeos/arc/trace/arc_trace_reader.cc

Issue 2400163003: arc: enable Android tracing in verified-boot mode (Closed)
Patch Set: Fix some nits Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/arc/trace/arc_trace_reader.cc
diff --git a/chrome/browser/chromeos/arc/trace/arc_trace_reader.cc b/chrome/browser/chromeos/arc/trace/arc_trace_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ba821d3ff3a33c99e93b47b43c712e1f0b7585c8
--- /dev/null
+++ b/chrome/browser/chromeos/arc/trace/arc_trace_reader.cc
@@ -0,0 +1,215 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/trace/arc_trace_reader.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/values.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace arc {
+
+namespace {
+
+#define ARC_TRACE_MESSAGE_LENGTH (1024 + 512)
Luis Héctor Chávez 2017/02/10 17:43:54 constexpr size_t kArcTraceMessageLength = 1024 + 5
Earl Ou 2017/03/22 11:38:26 Done in Android side.
+
+// Maximum data to be stored in the buffer.
+constexpr int kTraceBufferByteSize = 16 * 1024 * 1024; // 16MB
+
+} // namespace
+
+ArcTraceReader::ArcTraceReader()
+ : is_recording_(false), input_fd_(-1), recording_thread_(nullptr) {}
Luis Héctor Chávez 2017/02/10 17:43:55 these three can be set in the .h, that way you can
Earl Ou 2017/03/22 11:38:26 Done in Android side.
+
+void ArcTraceReader::Run() {
+ if (input_fd_.get() == -1) {
+ LOG(WARNING) << "No input FD is set before starting recording.";
+ return;
+ }
+
+ int ret;
+ fd_set fds;
+ timeval tv;
+ char buf[ARC_TRACE_MESSAGE_LENGTH];
+
+ while (is_recording_) {
+ FD_ZERO(&fds);
+ FD_SET(input_fd_.get(), &fds);
+
+ // Wait up to 1 second.
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ ret = TEMP_FAILURE_RETRY(
+ select(input_fd_.get() + 1, &fds, nullptr, nullptr, &tv));
+ if (ret < 0) {
+ LOG(ERROR) << "Unexpected error while recording ARC trace: "
+ << strerror(errno);
+ break;
+ }
+ if (!ret) // No data available.
+ continue;
+
+ ret = TEMP_FAILURE_RETRY(read(input_fd_.get(), buf, sizeof(buf) - 1));
Luis Héctor Chávez 2017/02/10 23:16:51 in any case, you should try to limit the amount of
Earl Ou 2017/03/22 11:38:26 This is moved to the Android side.
+ if (ret < 0) {
+ LOG(ERROR) << "Unexpected error while reading ARC trace: "
+ << strerror(errno);
+ break;
+ }
+ if (ret == 0) { // EOF
+ LOG(WARNING) << "EOF while recording ARC trace.";
+ break;
+ }
+ buf[ret] = 0; // Make sure the string is null terminated.
+ ParseAndSaveData(buf);
+ }
+}
+
+void ArcTraceReader::SetInputFD(base::ScopedFD fd) {
+ input_fd_ = std::move(fd);
+}
+
+void ArcTraceReader::StartRecord() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (is_recording_) {
+ LOG(WARNING) << "ARC trace reader already started.";
+ return;
+ }
+ is_recording_ = true;
+ current_data_size_ = 0;
+ trace_buffer_ = std::queue<std::string>(); // clean the queue.
+
+ recording_thread_.reset(
Luis Héctor Chávez 2017/02/10 17:43:54 How about using base::FileDescriptorWatcher::Watch
Luis Héctor Chávez 2017/02/10 23:16:51 You can also use something similar to https://cs.c
Earl Ou 2017/03/22 11:38:26 Done in arc_tracing_agent.cc
+ new base::DelegateSimpleThread(this, "ArcTraceReader"));
+ recording_thread_->Start();
+}
+
+void ArcTraceReader::StopRecord(const StopTracingCallback& callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (!is_recording_) {
+ LOG(WARNING) << "ARC trace reader was not started.";
+ callback.Run("");
+ return;
+ }
+ is_recording_ = false;
+ recording_thread_->Join();
+ recording_thread_.reset(nullptr);
Luis Héctor Chávez 2017/02/10 17:43:54 nit: recording_thread_.reset();
Earl Ou 2017/03/22 11:38:26 No reading thread now as suggested.
+
+ // TODO(shunshingou): run the following in a separated thread to avoid long
Luis Héctor Chávez 2017/02/10 17:43:55 This must be done in this CL, unfortunately. Worst
Luis Héctor Chávez 2017/02/10 17:48:03 D'Oh, this is a socket, not a pipe. Ignore the SIG
Earl Ou 2017/02/16 09:56:45 The comment here is for the processing of stringst
Earl Ou 2017/03/22 11:38:26 Now this is running in IO thread with WatchReadabl
+ // processing in UI thread.
+ std::stringstream ss;
+ bool is_first = true;
+ while (!trace_buffer_.empty()) {
+ if (!is_first)
+ ss << ",";
+ is_first = false;
+ ss << trace_buffer_.front();
+ trace_buffer_.pop();
+ }
+ callback.Run(ss.str());
+}
+
+void ArcTraceReader::WriteTraceEvent(char ph,
+ int pid,
+ int tid,
+ uint64_t ts,
+ uint64_t tts,
+ const std::string* name,
+ const int* count,
+ const int* id) {
+ base::DictionaryValue event;
+ event.SetString("cat", "android");
+ event.SetString("ph", std::string(1, ph));
+ event.SetInteger("pid", pid);
+ event.SetInteger("tid", tid);
+ event.SetDouble("ts", ts);
+ event.SetDouble("tts", tts);
+ if (name)
+ event.SetString("name", *name);
+
+ if (count)
+ event.SetInteger("args.count", *count);
+
+ if (id)
+ event.SetInteger("id", *id);
+
+ std::string json;
+ if (!base::JSONWriter::Write(event, &json)) {
+ // Bad data, shouldn't happen as the data is prepared by ourself.
Luis Héctor Chávez 2017/02/10 17:43:54 nit: ourselves.
Earl Ou 2017/03/22 11:38:26 Done on the Android side.
+ // Skip and return.
+ return;
+ }
+
+ current_data_size_ += json.size();
Luis Héctor Chávez 2017/02/10 17:43:54 Why do you still need this? Why can't you just sen
Luis Héctor Chávez 2017/02/10 23:16:51 Ignore the above comment, since it's the way the A
Earl Ou 2017/02/16 09:56:45 trace_buffer seems to be designed for Chrome traci
Earl Ou 2017/03/22 11:38:26 I'm using TraceBuffer in the new patch now.
+ trace_buffer_.emplace(std::move(json));
+
+ while (current_data_size_ > kTraceBufferByteSize) {
+ current_data_size_ -= trace_buffer_.front().size();
+ trace_buffer_.pop();
+ }
+}
+
+void ArcTraceReader::ParseAndSaveData(std::string data) {
Luis Héctor Chávez 2017/02/10 17:43:54 This might fail since |data| might contain multipl
Earl Ou 2017/02/16 09:56:46 The data would only have one trace event since we'
+ const std::vector<std::string> tokens =
+ base::SplitString(data, "|", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ // ph|pid|tid|ts|tts
+ if (tokens.size() < 5 || tokens[0].size() != 1) // bad data, skip.
+ return;
+
+ char ph = tokens[0][0];
+ int pid, tid;
+ uint64_t ts, tts;
+
+ if (!base::StringToInt(tokens[1], &pid) ||
+ !base::StringToInt(tokens[2], &tid) ||
+ !base::StringToUint64(tokens[3], &ts) ||
+ !base::StringToUint64(tokens[4], &tts)) {
+ return; // bad data, skip.
+ }
+
+ switch (ph) {
+ case 'B':
+ // B|pid|tid|ts|tts|name
+ if (tokens.size() != 6)
+ return; // bad data, skip.
+ WriteTraceEvent(ph, pid, tid, ts, tts, &tokens[5]);
+ break;
+ case 'E':
+ // E|pid|tid|ts|tts
+ WriteTraceEvent(ph, pid, tid, ts, tts);
+ break;
+ case 'F':
+ case 'S':
+ // F|pid|tid|ts|tts|name|value
+ int id;
+ if (tokens.size() != 7 || !base::StringToInt(tokens[6], &id))
+ return; // bad data, skip.
+ WriteTraceEvent(ph, pid, tid, ts, tts, &tokens[5], nullptr, &id);
+ break;
+ case 'C':
+ // C|pid|tid|ts|tts|name|value
+ int count;
+ if (tokens.size() != 7 || !base::StringToInt(tokens[6], &count))
+ return; // bad data, skip.
+ WriteTraceEvent(ph, pid, tid, ts, tts, &tokens[5], &count);
+ break;
+ }
+}
+
+} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698