| 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 |