OLD | NEW |
| (Empty) |
1 // Copyright 2013 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. | |
4 | |
5 #include <stdio.h> | |
6 #include <string.h> | |
7 | |
8 #include <algorithm> | |
9 #include <iostream> | |
10 | |
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 "mojo/shell/context.h" | |
19 #include "mojo/shell/switches.h" | |
20 | |
21 namespace mojo { | |
22 namespace shell { | |
23 namespace { | |
24 | |
25 // Whether we're currently tracing. | |
26 bool g_tracing = false; | |
27 | |
28 // Number of tracing blocks written. | |
29 uint32_t g_blocks = 0; | |
30 | |
31 // Trace file, if open. | |
32 FILE* g_trace_file = nullptr; | |
33 | |
34 void WriteTraceDataCollected( | |
35 base::WaitableEvent* event, | |
36 const scoped_refptr<base::RefCountedString>& events_str, | |
37 bool has_more_events) { | |
38 if (g_blocks) { | |
39 fwrite(",", 1, 1, g_trace_file); | |
40 } | |
41 | |
42 ++g_blocks; | |
43 fwrite(events_str->data().c_str(), 1, events_str->data().length(), | |
44 g_trace_file); | |
45 if (!has_more_events) { | |
46 static const char kEnd[] = "]}"; | |
47 fwrite(kEnd, 1, strlen(kEnd), g_trace_file); | |
48 PCHECK(fclose(g_trace_file) == 0); | |
49 g_trace_file = nullptr; | |
50 event->Signal(); | |
51 } | |
52 } | |
53 | |
54 void EndTraceAndFlush(base::WaitableEvent* event) { | |
55 g_trace_file = fopen("mojo_shell.trace", "w+"); | |
56 PCHECK(g_trace_file); | |
57 static const char kStart[] = "{\"traceEvents\":["; | |
58 fwrite(kStart, 1, strlen(kStart), g_trace_file); | |
59 base::trace_event::TraceLog::GetInstance()->SetDisabled(); | |
60 base::trace_event::TraceLog::GetInstance()->Flush( | |
61 base::Bind(&WriteTraceDataCollected, base::Unretained(event))); | |
62 } | |
63 | |
64 void StopTracingAndFlushToDisk() { | |
65 g_tracing = false; | |
66 base::trace_event::TraceLog::GetInstance()->SetDisabled(); | |
67 base::WaitableEvent flush_complete_event(false, false); | |
68 // TraceLog::Flush requires a message loop but we've already shut ours down. | |
69 // Spin up a new thread to flush things out. | |
70 base::Thread flush_thread("mojo_shell_trace_event_flush"); | |
71 flush_thread.Start(); | |
72 flush_thread.message_loop()->PostTask( | |
73 FROM_HERE, | |
74 base::Bind(EndTraceAndFlush, base::Unretained(&flush_complete_event))); | |
75 flush_complete_event.Wait(); | |
76 } | |
77 | |
78 void StartApp(mojo::shell::Context* context) { | |
79 // If a mojo app isn't specified (i.e. for an apptest), run the mojo shell's | |
80 // window manager. | |
81 GURL app_url(GURL("mojo:window_manager")); | |
82 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
83 base::CommandLine::StringVector args = command_line->GetArgs(); | |
84 for (size_t i = 0; i < args.size(); ++i) { | |
85 GURL possible_app(args[i]); | |
86 if (possible_app.SchemeIs("mojo")) { | |
87 app_url = possible_app; | |
88 break; | |
89 } | |
90 } | |
91 | |
92 context->Run(app_url); | |
93 } | |
94 | |
95 } // namespace | |
96 | |
97 int LauncherProcessMain(int argc, char** argv) { | |
98 const base::CommandLine& command_line = | |
99 *base::CommandLine::ForCurrentProcess(); | |
100 if (command_line.HasSwitch(switches::kTraceStartup)) { | |
101 g_tracing = true; | |
102 base::trace_event::CategoryFilter category_filter( | |
103 command_line.GetSwitchValueASCII(switches::kTraceStartup)); | |
104 base::trace_event::TraceLog::GetInstance()->SetEnabled( | |
105 category_filter, base::trace_event::TraceLog::RECORDING_MODE, | |
106 base::trace_event::TraceOptions(base::trace_event::RECORD_UNTIL_FULL)); | |
107 } | |
108 | |
109 // We want the shell::Context to outlive the MessageLoop so that pipes are | |
110 // all gracefully closed / error-out before we try to shut the Context down. | |
111 mojo::shell::Context shell_context; | |
112 { | |
113 base::MessageLoop message_loop; | |
114 if (!shell_context.Init()) { | |
115 return 0; | |
116 } | |
117 if (g_tracing) { | |
118 message_loop.PostDelayedTask(FROM_HERE, | |
119 base::Bind(StopTracingAndFlushToDisk), | |
120 base::TimeDelta::FromSeconds(5)); | |
121 } | |
122 | |
123 message_loop.PostTask(FROM_HERE, base::Bind(&StartApp, &shell_context)); | |
124 message_loop.Run(); | |
125 | |
126 // Must be called before |message_loop| is destroyed. | |
127 shell_context.Shutdown(); | |
128 } | |
129 | |
130 if (g_tracing) | |
131 StopTracingAndFlushToDisk(); | |
132 return 0; | |
133 } | |
134 | |
135 } // namespace shell | |
136 } // namespace mojo | |
OLD | NEW |