Commit 70929846 authored by shunhsingou's avatar shunhsingou Committed by Commit bot

arc: enable Android tracing in verified-boot mode

In verified-boot mode, ftrace trace_marker is not allowed for writting
due to security concern. As an altenative, we use a socket for processes in
Android to write trace events, and send back the trace data via Mojo
handle.

All change set includes:
- http://crrev.com/2400163003 (Chromium)
- http://ag/2028075 (Android system/core)
- http://ag/1738271 (Android device/google/cheets2)

BUG=653795
TEST=Run chrome://tracing and see events from Android.

Review-Url: https://codereview.chromium.org/2400163003
Cr-Commit-Position: refs/heads/master@{#468306}
parent c362658d
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "components/arc/arc_bridge_service.h" #include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service_manager.h" #include "components/arc/arc_service_manager.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace arc { namespace arc {
...@@ -59,7 +60,7 @@ void ArcTracingBridge::OnCategoriesReady( ...@@ -59,7 +60,7 @@ void ArcTracingBridge::OnCategoriesReady(
// ignored when calling |StartTracing|. // ignored when calling |StartTracing|.
categories_.clear(); categories_.clear();
for (const auto& category : categories) { for (const auto& category : categories) {
categories_.push_back({category, kCategoryPrefix + category}); categories_.emplace_back(Category{category, kCategoryPrefix + category});
// Show the category name in the selection UI. // Show the category name in the selection UI.
base::trace_event::TraceLog::GetCategoryGroupEnabled( base::trace_event::TraceLog::GetCategoryGroupEnabled(
categories_.back().full_name.c_str()); categories_.back().full_name.c_str());
...@@ -68,6 +69,7 @@ void ArcTracingBridge::OnCategoriesReady( ...@@ -68,6 +69,7 @@ void ArcTracingBridge::OnCategoriesReady(
void ArcTracingBridge::StartTracing( void ArcTracingBridge::StartTracing(
const base::trace_event::TraceConfig& trace_config, const base::trace_event::TraceConfig& trace_config,
base::ScopedFD write_fd,
const StartTracingCallback& callback) { const StartTracingCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -87,7 +89,9 @@ void ArcTracingBridge::StartTracing( ...@@ -87,7 +89,9 @@ void ArcTracingBridge::StartTracing(
selected_categories.push_back(category.name); selected_categories.push_back(category.name);
} }
tracing_instance->StartTracing(selected_categories, callback); tracing_instance->StartTracing(selected_categories,
mojo::WrapPlatformFile(write_fd.release()),
callback);
} }
void ArcTracingBridge::StopTracing(const StopTracingCallback& callback) { void ArcTracingBridge::StopTracing(const StopTracingCallback& callback) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/files/scoped_file.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
...@@ -34,6 +35,7 @@ class ArcTracingBridge ...@@ -34,6 +35,7 @@ class ArcTracingBridge
// content::ArcTracingAgent::Delegate overrides: // content::ArcTracingAgent::Delegate overrides:
void StartTracing(const base::trace_event::TraceConfig& trace_config, void StartTracing(const base::trace_event::TraceConfig& trace_config,
base::ScopedFD write_fd,
const StartTracingCallback& callback) override; const StartTracingCallback& callback) override;
void StopTracing(const StopTracingCallback& callback) override; void StopTracing(const StopTracingCallback& callback) override;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Next MinVersion: 1 // Next MinVersion: 2
module arc.mojom; module arc.mojom;
...@@ -10,8 +10,11 @@ interface TracingInstance { ...@@ -10,8 +10,11 @@ interface TracingInstance {
// Queries available tracing categories in the container. // Queries available tracing categories in the container.
QueryAvailableCategories@0() => (array<string> categories); QueryAvailableCategories@0() => (array<string> categories);
// Starts tracing in the container with the given categories. // Starts tracing in the container with the given categories. A handle is
StartTracing@1(array<string> categories) => (bool success); // passed to the client for sending trace events back to the host. The client
// should send trace event as a JSON object in each write.
StartTracing@1(array<string> categories,
[MinVersion=1] handle? socket) => (bool success);
// Stops tracing in the container. // Stops tracing in the container.
StopTracing@2() => (bool success); StopTracing@2() => (bool success);
......
...@@ -1415,8 +1415,6 @@ source_set("browser") { ...@@ -1415,8 +1415,6 @@ source_set("browser") {
"streams/stream_write_observer.h", "streams/stream_write_observer.h",
"theme_helper_mac.h", "theme_helper_mac.h",
"theme_helper_mac.mm", "theme_helper_mac.mm",
"tracing/arc_tracing_agent.cc",
"tracing/arc_tracing_agent.h",
"tracing/background_memory_tracing_observer.cc", "tracing/background_memory_tracing_observer.cc",
"tracing/background_memory_tracing_observer.h", "tracing/background_memory_tracing_observer.h",
"tracing/background_tracing_config_impl.cc", "tracing/background_tracing_config_impl.cc",
...@@ -1546,6 +1544,12 @@ source_set("browser") { ...@@ -1546,6 +1544,12 @@ source_set("browser") {
"tracing/power_tracing_agent.h", "tracing/power_tracing_agent.h",
] ]
} }
if (is_chromeos) {
sources += [
"tracing/arc_tracing_agent.cc",
"tracing/arc_tracing_agent.h",
]
}
if (enable_webrtc) { if (enable_webrtc) {
sources += [ sources += [
......
...@@ -4,24 +4,123 @@ ...@@ -4,24 +4,123 @@
#include "content/browser/tracing/arc_tracing_agent.h" #include "content/browser/tracing/arc_tracing_agent.h"
#include <memory>
#include <string> #include <string>
#include <utility>
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/threading/thread_checker.h" #include "base/memory/weak_ptr.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "cc/base/ring_buffer.h"
#include "content/public/browser/browser_thread.h"
namespace content { namespace content {
namespace { namespace {
// The maximum size used to store one trace event. The ad hoc trace format for
// atrace is 1024 bytes. Here we add additional size as we're using JSON and
// have additional data fields.
constexpr size_t kArcTraceMessageLength = 1024 + 512;
constexpr char kArcTracingAgentName[] = "arc"; constexpr char kArcTracingAgentName[] = "arc";
constexpr char kArcTraceLabel[] = "ArcTraceEvents"; constexpr char kArcTraceLabel[] = "ArcTraceEvents";
void OnStopTracing(bool success) { // Number of events for the ring buffer.
DLOG_IF(WARNING, !success) << "Failed to stop ARC tracing."; constexpr size_t kTraceEventBufferSize = 64000;
}
// A helper class for reading trace data from the client side. We separate this
// from |ArcTracingAgentImpl| to isolate the logic that runs on browser's IO
// thread. All the functions in this class except for constructor, destructor,
// and |GetWeakPtr| are expected to be run on browser's IO thread.
class ArcTracingReader {
public:
using StopTracingCallback =
base::Callback<void(const scoped_refptr<base::RefCountedString>&)>;
ArcTracingReader() : weak_ptr_factory_(this) {}
void StartTracing(base::ScopedFD read_fd) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
read_fd_ = std::move(read_fd);
// We don't use the weak pointer returned by |GetWeakPtr| to avoid using it
// on different task runner. Instead, we use |base::Unretained| here as
// |fd_watcher_| is always destroyed before |this| is destroyed.
fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
read_fd_.get(), base::Bind(&ArcTracingReader::OnTraceDataAvailable,
base::Unretained(this)));
}
void OnTraceDataAvailable() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
char buf[kArcTraceMessageLength];
std::vector<base::ScopedFD> unused_fds;
ssize_t n = base::UnixDomainSocket::RecvMsg(
read_fd_.get(), buf, kArcTraceMessageLength, &unused_fds);
// When EOF, return and do nothing. The clean up is done in StopTracing.
if (n == 0)
return;
if (n < 0) {
DPLOG(WARNING) << "Unexpected error while reading trace from client.";
// Do nothing here as StopTracing will do the clean up and the existing
// trace logs will be returned.
return;
}
if (n > static_cast<ssize_t>(kArcTraceMessageLength)) {
DLOG(WARNING) << "Unexpected data size when reading trace from client.";
return;
}
ring_buffer_.SaveToBuffer(std::string(buf, n));
}
void StopTracing(const StopTracingCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
fd_watcher_.reset();
read_fd_.reset();
bool append_comma = false;
std::string data;
for (auto it = ring_buffer_.Begin(); it; ++it) {
if (append_comma)
data.append(",");
else
append_comma = true;
data.append(**it);
}
ring_buffer_.Clear();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(callback, base::RefCountedString::TakeString(&data)));
}
base::WeakPtr<ArcTracingReader> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::ScopedFD read_fd_;
std::unique_ptr<base::FileDescriptorWatcher::Controller> fd_watcher_;
cc::RingBuffer<std::string, kTraceEventBufferSize> ring_buffer_;
// NOTE: Weak pointers must be invalidated before all other member variables
// so it must be the last member.
base::WeakPtrFactory<ArcTracingReader> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcTracingReader);
};
class ArcTracingAgentImpl : public ArcTracingAgent { class ArcTracingAgentImpl : public ArcTracingAgent {
public: public:
...@@ -32,10 +131,16 @@ class ArcTracingAgentImpl : public ArcTracingAgent { ...@@ -32,10 +131,16 @@ class ArcTracingAgentImpl : public ArcTracingAgent {
void StartAgentTracing(const base::trace_event::TraceConfig& trace_config, void StartAgentTracing(const base::trace_event::TraceConfig& trace_config,
const StartAgentTracingCallback& callback) override { const StartAgentTracingCallback& callback) override {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_CURRENTLY_ON(BrowserThread::UI);
// delegate_ may be nullptr if ARC is not enabled on the system. In such // delegate_ may be nullptr if ARC is not enabled on the system. In such
// case, simply do nothing. // case, simply do nothing.
if (!delegate_) { bool success = (delegate_ != nullptr);
base::ScopedFD write_fd, read_fd;
success = success && CreateSocketPair(&read_fd, &write_fd);
if (!success) {
// Use PostTask as the convention of TracingAgent. The caller expects // Use PostTask as the convention of TracingAgent. The caller expects
// callback to be called after this function returns. // callback to be called after this function returns.
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
...@@ -43,27 +148,33 @@ class ArcTracingAgentImpl : public ArcTracingAgent { ...@@ -43,27 +148,33 @@ class ArcTracingAgentImpl : public ArcTracingAgent {
return; return;
} }
delegate_->StartTracing(trace_config, BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ArcTracingReader::StartTracing, reader_.GetWeakPtr(),
base::Passed(&read_fd)));
delegate_->StartTracing(trace_config, std::move(write_fd),
base::Bind(callback, GetTracingAgentName())); base::Bind(callback, GetTracingAgentName()));
} }
void StopAgentTracing(const StopAgentTracingCallback& callback) override { void StopAgentTracing(const StopAgentTracingCallback& callback) override {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (delegate_)
delegate_->StopTracing(base::Bind(OnStopTracing));
// Trace data is collect via systrace (debugd) in dev-mode. Simply if (is_stopping_) {
// return empty data here. DLOG(WARNING) << "Already working on stopping ArcTracingAgent.";
std::string no_data; return;
base::ThreadTaskRunnerHandle::Get()->PostTask( }
FROM_HERE, is_stopping_ = true;
base::Bind(callback, GetTracingAgentName(), GetTraceEventLabel(), if (delegate_) {
base::RefCountedString::TakeString(&no_data))); delegate_->StopTracing(
base::Bind(&ArcTracingAgentImpl::OnArcTracingStopped,
weak_ptr_factory_.GetWeakPtr(), callback));
}
} }
// ArcTracingAgent overrides: // ArcTracingAgent overrides:
void SetDelegate(Delegate* delegate) override { void SetDelegate(Delegate* delegate) override {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_CURRENTLY_ON(BrowserThread::UI);
delegate_ = delegate; delegate_ = delegate;
} }
...@@ -76,11 +187,48 @@ class ArcTracingAgentImpl : public ArcTracingAgent { ...@@ -76,11 +187,48 @@ class ArcTracingAgentImpl : public ArcTracingAgent {
// by the Singleton class. // by the Singleton class.
friend struct base::DefaultSingletonTraits<ArcTracingAgentImpl>; friend struct base::DefaultSingletonTraits<ArcTracingAgentImpl>;
ArcTracingAgentImpl() = default; ArcTracingAgentImpl() : weak_ptr_factory_(this) {}
~ArcTracingAgentImpl() override = default; ~ArcTracingAgentImpl() override = default;
void OnArcTracingStopped(const StopAgentTracingCallback& callback,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!success) {
DLOG(WARNING) << "Failed to stop ARC tracing.";
callback.Run(GetTracingAgentName(), GetTraceEventLabel(),
new base::RefCountedString());
is_stopping_ = false;
return;
}
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ArcTracingReader::StopTracing, reader_.GetWeakPtr(),
base::Bind(&ArcTracingAgentImpl::OnTracingReaderStopped,
weak_ptr_factory_.GetWeakPtr(), callback)));
}
void OnTracingReaderStopped(
const StopAgentTracingCallback& callback,
const scoped_refptr<base::RefCountedString>& data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
callback.Run(GetTracingAgentName(), GetTraceEventLabel(), data);
is_stopping_ = false;
}
Delegate* delegate_ = nullptr; // Owned by ArcServiceLauncher. Delegate* delegate_ = nullptr; // Owned by ArcServiceLauncher.
base::ThreadChecker thread_checker_; // We use |reader_.GetWeakPtr()| when binding callbacks with its functions.
// Notes that the weak pointer returned by it can only be deferenced or
// invalided in the same task runner to avoid racing condition. The
// destruction of |reader_| is also a source of invalidation. However, we're
// lucky as we're using |ArcTracingAgentImpl| as a singleton, the
// destruction is always performed after all MessageLoops are destroyed, and
// thus there are no race conditions in such situation.
ArcTracingReader reader_;
bool is_stopping_ = false;
// NOTE: Weak pointers must be invalidated before all other member variables
// so it must be the last member.
base::WeakPtrFactory<ArcTracingAgentImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcTracingAgentImpl); DISALLOW_COPY_AND_ASSIGN(ArcTracingAgentImpl);
}; };
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_TRACING_ARC_TRACING_AGENT_H_ #define CONTENT_BROWSER_TRACING_ARC_TRACING_AGENT_H_
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/files/scoped_file.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "base/trace_event/tracing_agent.h" #include "base/trace_event/tracing_agent.h"
...@@ -33,6 +34,7 @@ class CONTENT_EXPORT ArcTracingAgent : public base::trace_event::TracingAgent { ...@@ -33,6 +34,7 @@ class CONTENT_EXPORT ArcTracingAgent : public base::trace_event::TracingAgent {
// Starts tracing in ARC container. // Starts tracing in ARC container.
virtual void StartTracing( virtual void StartTracing(
const base::trace_event::TraceConfig& trace_config, const base::trace_event::TraceConfig& trace_config,
base::ScopedFD write_fd,
const StartTracingCallback& callback) = 0; const StartTracingCallback& callback) = 0;
// Stops tracing in ARC container. // Stops tracing in ARC container.
......
...@@ -598,10 +598,11 @@ void TracingControllerImpl::OnEndAgentTracingAcked( ...@@ -598,10 +598,11 @@ void TracingControllerImpl::OnEndAgentTracingAcked(
// The Windows kernel events are kept into a JSON format stored as string // The Windows kernel events are kept into a JSON format stored as string
// and must not be escaped. // and must not be escaped.
trace_data_sink_->AddAgentTrace(events_label, events_str_ptr->data()); trace_data_sink_->AddAgentTrace(events_label, events_str_ptr->data());
} else if (agent_name != kArcTracingAgentName) { } else if (agent_name == kArcTracingAgentName) {
// ARC trace data is obtained via systrace. Ignore the empty data. // The ARC events are kept into a JSON format stored as string
// Quote other trace data as JSON strings and merge them into // and must not be escaped.
// |trace_data_sink_|. trace_data_sink_->AddTraceChunk(events_str_ptr->data());
} else {
trace_data_sink_->AddAgentTrace( trace_data_sink_->AddAgentTrace(
events_label, base::GetQuotedJSONString(events_str_ptr->data())); events_label, base::GetQuotedJSONString(events_str_ptr->data()));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment