1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
11 #include "base/base_switches.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/files/file_util.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/trace_event/trace_event.h"
18 #include "components/tracing/startup_tracing.h"
19 #include "mandoline/app/core_services_initialization.h"
20 #include "mandoline/app/desktop/launcher_process.h"
21 #include "mojo/runner/context.h"
22 #include "mojo/runner/switches.h"
27 // Whether we're currently tracing.
28 bool g_tracing
= false;
30 // Number of tracing blocks written.
31 uint32_t g_blocks
= 0;
33 // Trace file, if open.
34 FILE* g_trace_file
= nullptr;
36 void WriteTraceDataCollected(
37 base::WaitableEvent
* event
,
38 const scoped_refptr
<base::RefCountedString
>& events_str
,
39 bool has_more_events
) {
41 fwrite(",", 1, 1, g_trace_file
);
45 fwrite(events_str
->data().c_str(), 1, events_str
->data().length(),
47 if (!has_more_events
) {
48 static const char kEnd
[] = "]}";
49 fwrite(kEnd
, 1, strlen(kEnd
), g_trace_file
);
50 PCHECK(fclose(g_trace_file
) == 0);
51 g_trace_file
= nullptr;
56 void EndTraceAndFlush(base::WaitableEvent
* event
) {
57 g_trace_file
= fopen("mojo_shell.trace", "w+");
59 static const char kStart
[] = "{\"traceEvents\":[";
60 fwrite(kStart
, 1, strlen(kStart
), g_trace_file
);
61 base::trace_event::TraceLog::GetInstance()->SetDisabled();
62 base::trace_event::TraceLog::GetInstance()->Flush(
63 base::Bind(&WriteTraceDataCollected
, base::Unretained(event
)));
66 void StopTracingAndFlushToDisk() {
68 base::trace_event::TraceLog::GetInstance()->SetDisabled();
69 base::WaitableEvent
flush_complete_event(false, false);
70 // TraceLog::Flush requires a message loop but we've already shut ours down.
71 // Spin up a new thread to flush things out.
72 base::Thread
flush_thread("mojo_shell_trace_event_flush");
74 flush_thread
.message_loop()->PostTask(
76 base::Bind(EndTraceAndFlush
, base::Unretained(&flush_complete_event
)));
77 flush_complete_event
.Wait();
82 int LauncherProcessMain(int argc
, char** argv
) {
83 const base::CommandLine
& command_line
=
84 *base::CommandLine::ForCurrentProcess();
85 if (command_line
.HasSwitch(switches::kTraceStartup
)) {
87 base::trace_event::TraceConfig
trace_config(
88 command_line
.GetSwitchValueASCII(switches::kTraceStartup
),
89 base::trace_event::RECORD_UNTIL_FULL
);
90 base::trace_event::TraceLog::GetInstance()->SetEnabled(
91 trace_config
, base::trace_event::TraceLog::RECORDING_MODE
);
93 // |g_tracing| is not touched in this case and Telemetry will stop tracing
95 tracing::EnableStartupTracingIfConfigFileExists();
98 // We want the runner::Context to outlive the MessageLoop so that pipes are
99 // all gracefully closed / error-out before we try to shut the Context down.
100 mojo::runner::Context shell_context
;
101 InitCoreServicesForContext(&shell_context
);
103 base::MessageLoop message_loop
;
104 if (!shell_context
.Init()) {
108 message_loop
.PostDelayedTask(FROM_HERE
,
109 base::Bind(StopTracingAndFlushToDisk
),
110 base::TimeDelta::FromSeconds(5));
113 message_loop
.PostTask(FROM_HERE
,
114 base::Bind(&mojo::runner::Context::Run
,
115 base::Unretained(&shell_context
),
116 GURL("mojo:browser")));
119 // Must be called before |message_loop| is destroyed.
120 shell_context
.Shutdown();
124 StopTracingAndFlushToDisk();
128 } // namespace mandoline