Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/debug/profiler.h" | 8 #include "base/debug/profiler.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 11 #include "mojo/application/application_runner_chromium.h" | 11 #include "mojo/application/application_runner_chromium.h" |
| 12 #include "mojo/common/data_pipe_utils.h" | |
| 12 #include "mojo/public/c/system/main.h" | 13 #include "mojo/public/c/system/main.h" |
| 13 #include "mojo/public/cpp/application/application_delegate.h" | 14 #include "mojo/public/cpp/application/application_delegate.h" |
| 14 #include "mojo/public/cpp/application/application_impl.h" | 15 #include "mojo/public/cpp/application/application_impl.h" |
| 16 #include "mojo/public/cpp/bindings/strong_binding.h" | |
| 15 #include "mojo/services/window_manager/public/interfaces/window_manager.mojom.h" | 17 #include "mojo/services/window_manager/public/interfaces/window_manager.mojom.h" |
| 16 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 17 #include "net/server/http_server.h" | 19 #include "services/http_server/public/http_server.mojom.h" |
| 18 #include "net/server/http_server_request_info.h" | 20 #include "services/http_server/public/http_server_factory.mojom.h" |
| 19 #include "net/socket/tcp_server_socket.h" | 21 #include "services/http_server/public/http_server_util.h" |
| 20 #include "services/tracing/tracing.mojom.h" | 22 #include "services/tracing/tracing.mojom.h" |
| 21 #include "sky/tools/debugger/trace_collector.h" | 23 #include "sky/tools/debugger/trace_collector.h" |
| 22 | 24 |
| 23 namespace sky { | 25 namespace sky { |
| 24 namespace debugger { | 26 namespace debugger { |
| 25 namespace { | |
| 26 | 27 |
| 27 const size_t kMinSendBufferSize = 1024 * 1024; | 28 class SkyDebugger : public mojo::ApplicationDelegate { |
| 28 } | |
| 29 | |
| 30 class SkyDebugger : public mojo::ApplicationDelegate, | |
| 31 public net::HttpServer::Delegate { | |
| 32 public: | 29 public: |
| 33 SkyDebugger() : is_tracing_(false) {} | 30 SkyDebugger() : is_tracing_(false) {} |
| 34 virtual ~SkyDebugger() {} | 31 virtual ~SkyDebugger() {} |
| 35 | 32 |
| 36 private: | 33 private: |
| 34 typedef mojo::Callback<void(http_server::HttpResponsePtr)> | |
| 35 HttpResponseCallback; | |
|
qsr
2015/02/17 10:33:18
This typedef is already defined for you in the gen
ppi
2015/02/17 12:05:24
Done.
| |
| 36 class Handler : public http_server::HttpHandler { | |
|
qsr
2015/02/17 10:33:18
You can probably get rid of this class by having S
ppi
2015/02/17 12:05:24
Done.
| |
| 37 public: | |
| 38 Handler(mojo::InterfaceRequest<HttpHandler> request, SkyDebugger* debugger) | |
| 39 : binding_(this, request.Pass()), debugger_(debugger) {} | |
| 40 | |
| 41 private: | |
| 42 // http_server::HttpHandler: | |
| 43 void HandleRequest(http_server::HttpRequestPtr request, | |
| 44 const HttpResponseCallback& callback) override { | |
| 45 debugger_->OnHttpRequest(request.Pass(), callback); | |
| 46 } | |
| 47 | |
| 48 mojo::StrongBinding<http_server::HttpHandler> binding_; | |
| 49 SkyDebugger* debugger_; | |
| 50 }; | |
| 51 | |
| 37 // Overridden from mojo::ApplicationDelegate: | 52 // Overridden from mojo::ApplicationDelegate: |
| 38 virtual void Initialize(mojo::ApplicationImpl* app) override { | 53 virtual void Initialize(mojo::ApplicationImpl* app) override { |
| 39 app->ConnectToService("mojo:tracing", &tracing_); | 54 app->ConnectToService("mojo:tracing", &tracing_); |
| 55 app->ConnectToService("mojo:window_manager", &window_manager_); | |
| 56 | |
| 40 // Format: --args-for="app_url command_port" | 57 // Format: --args-for="app_url command_port" |
| 41 if (app->args().size() < 2) { | 58 if (app->args().size() < 2) { |
| 42 LOG(ERROR) << "--args-for required to specify command_port"; | 59 LOG(ERROR) << "--args-for required to specify command_port"; |
| 43 mojo::ApplicationImpl::Terminate(); | 60 mojo::ApplicationImpl::Terminate(); |
| 44 return; | 61 return; |
| 45 } | 62 } |
| 63 base::StringToUint(app->args()[1], &command_port_); | |
| 64 http_server::HttpServerFactoryPtr http_server_factory; | |
| 65 app->ConnectToService("mojo:http_server", &http_server_factory); | |
| 66 http_server_factory->CreateHttpServer(GetProxy(&http_server_).Pass(), | |
| 67 command_port_); | |
| 46 | 68 |
| 47 base::StringToUint(app->args()[1], &command_port_); | 69 http_server::HttpHandlerPtr handler_ptr; |
| 48 | 70 new Handler(GetProxy(&handler_ptr).Pass(), this); |
| 49 scoped_ptr<net::ServerSocket> server_socket( | 71 http_server_->SetHandler(".*", handler_ptr.Pass(), |
| 50 new net::TCPServerSocket(NULL, net::NetLog::Source())); | 72 [](bool result) { DCHECK(result); }); |
| 51 int result = | |
| 52 server_socket->ListenWithAddressAndPort("0.0.0.0", command_port_, 1); | |
| 53 if (result != net::OK) { | |
| 54 LOG(ERROR) << "Failed to bind to port " << command_port_ | |
| 55 << " skydb commands will not work."; | |
| 56 mojo::ApplicationImpl::Terminate(); | |
| 57 return; | |
| 58 } | |
| 59 web_server_.reset(new net::HttpServer(server_socket.Pass(), this)); | |
| 60 | |
| 61 app->ConnectToService("mojo:window_manager", &window_manager_); | |
| 62 } | 73 } |
| 63 | 74 |
| 64 virtual bool ConfigureIncomingConnection( | 75 virtual bool ConfigureIncomingConnection( |
| 65 mojo::ApplicationConnection* connection) override { | 76 mojo::ApplicationConnection* connection) override { |
| 66 return true; | 77 return true; |
| 67 } | 78 } |
| 68 | 79 |
| 69 // net::HttpServer::Delegate | 80 void OnHttpRequest(http_server::HttpRequestPtr request, |
| 70 void OnConnect(int connection_id) override {} | 81 const HttpResponseCallback& callback) { |
| 71 | |
| 72 void OnClose(int connection_id) override {} | |
| 73 | |
| 74 void OnHttpRequest(int connection_id, | |
| 75 const net::HttpServerRequestInfo& info) override { | |
| 76 // FIXME: We should use use a fancier lookup system more like what | 82 // FIXME: We should use use a fancier lookup system more like what |
| 77 // services/http_server/http_server.cc does with AddHandler. | 83 // services/http_server/http_server.cc does with AddHandler. |
| 78 if (info.path == "/reload") | 84 if (request->relative_url == "/reload") { |
| 79 Load(connection_id, url_); | 85 Load(callback, url_); |
| 80 else if (info.path == "/quit") | 86 } else if (request->relative_url == "/quit") { |
| 81 Quit(connection_id); | 87 Quit(); |
| 82 else if (info.path == "/load") | 88 } else if (request->relative_url == "/load") { |
| 83 Load(connection_id, info.data); | 89 std::string url; |
| 84 else if (info.path == "/start_profiling") | 90 mojo::common::BlockingCopyToString(request->body.Pass(), &url); |
| 85 StartProfiling(connection_id); | 91 Load(callback, url); |
| 86 else if (info.path == "/stop_profiling") | 92 } else if (request->relative_url == "/start_profiling") { |
| 87 StopProfiling(connection_id); | 93 StartProfiling(callback); |
| 88 else if (info.path == "/start_tracing") | 94 } else if (request->relative_url == "/stop_profiling") { |
| 89 StartTracing(connection_id); | 95 StopProfiling(callback); |
| 90 else if (info.path == "/stop_tracing") | 96 } else if (request->relative_url == "/start_tracing") { |
| 91 StopTracing(connection_id); | 97 StartTracing(callback); |
| 92 else | 98 } else if (request->relative_url == "/stop_tracing") { |
| 93 Help(info.path, connection_id); | 99 StopTracing(callback); |
| 100 } else { | |
| 101 Help(callback, request->relative_url); | |
| 102 } | |
| 94 } | 103 } |
| 95 | 104 |
| 96 void OnWebSocketRequest(int connection_id, | 105 void Error(const HttpResponseCallback& callback, std::string message) { |
| 97 const net::HttpServerRequestInfo& info) override { | 106 callback.Run(http_server::CreateHttpResponse(500, message)); |
| 98 Error(connection_id, "OnWebSocketRequest not implemented"); | |
| 99 } | 107 } |
| 100 | 108 |
| 101 void OnWebSocketMessage(int connection_id, const std::string& data) override { | 109 void Respond(const HttpResponseCallback& callback, std::string response) { |
| 102 Error(connection_id, "OnWebSocketMessage not implemented"); | 110 callback.Run(http_server::CreateHttpResponse(200, response)); |
| 103 } | 111 } |
| 104 | 112 |
| 105 void Error(int connection_id, std::string message) { | 113 void Help(const HttpResponseCallback& callback, std::string path) { |
| 106 web_server_->Send500(connection_id, message); | |
| 107 } | |
| 108 | |
| 109 void Respond(int connection_id, std::string response) { | |
| 110 // When sending tracing data back over the wire to the client, we can blow | |
| 111 // through the default send buffer size. | |
| 112 web_server_->SetSendBufferSize( | |
| 113 connection_id, std::max(kMinSendBufferSize, response.length())); | |
| 114 web_server_->Send200(connection_id, response, "text/plain"); | |
| 115 } | |
| 116 | |
| 117 void Help(std::string path, int connection_id) { | |
| 118 std::string help = base::StringPrintf( | 114 std::string help = base::StringPrintf( |
| 119 "Sky Debugger running on port %d\n" | 115 "Sky Debugger running on port %d\n" |
| 120 "Supported URLs:\n" | 116 "Supported URLs:\n" |
| 121 "/reload -- Reload the current page\n" | 117 "/reload -- Reload the current page\n" |
| 122 "/quit -- Quit\n" | 118 "/quit -- Quit\n" |
| 123 "/load -- Load a new URL, url in POST body.\n", | 119 "/load -- Load a new URL, url in POST body.\n", |
| 124 command_port_); | 120 command_port_); |
| 125 if (path != "/") | 121 if (path != "/") |
| 126 help = "Unknown path: " + path + "\n\n" + help; | 122 help = "Unknown path: " + path + "\n\n" + help; |
| 127 Respond(connection_id, help); | 123 Respond(callback, help); |
| 128 } | 124 } |
| 129 | 125 |
| 130 void Load(int connection_id, std::string url) { | 126 void Load(const HttpResponseCallback& callback, std::string url) { |
| 131 url_ = url; | 127 url_ = url; |
| 132 Reload(); | 128 Reload(); |
| 133 std::string response = std::string("Loaded ") + url + "\n"; | 129 std::string response = std::string("Loaded ") + url + "\n"; |
| 134 Respond(connection_id, response); | 130 Respond(callback, response); |
| 135 } | 131 } |
| 136 | 132 |
| 137 void Reload() { | 133 void Reload() { |
| 138 // SimpleWindowManager will wire up necessary services on our behalf. | 134 // SimpleWindowManager will wire up necessary services on our behalf. |
| 139 window_manager_->Embed(url_, nullptr, nullptr); | 135 window_manager_->Embed(url_, nullptr, nullptr); |
| 140 } | 136 } |
| 141 | 137 |
| 142 void Quit(int connection_id) { | 138 void Quit() { |
| 143 // TODO(eseidel): We should orderly shutdown once mojo can. | 139 // TODO(eseidel): We should orderly shutdown once mojo can. |
| 144 exit(0); | 140 exit(0); |
| 145 } | 141 } |
| 146 | 142 |
| 147 void StartTracing(int connection_id) { | 143 void StartTracing(const HttpResponseCallback& callback) { |
| 148 if (is_tracing_) { | 144 if (is_tracing_) { |
| 149 Error(connection_id, "Already tracing. Use stop_tracing to stop.\n"); | 145 Error(callback, "Already tracing. Use stop_tracing to stop.\n"); |
| 150 return; | 146 return; |
| 151 } | 147 } |
| 152 | 148 |
| 153 is_tracing_ = true; | 149 is_tracing_ = true; |
| 154 mojo::DataPipe pipe; | 150 mojo::DataPipe pipe; |
| 155 tracing_->Start(pipe.producer_handle.Pass(), mojo::String("*")); | 151 tracing_->Start(pipe.producer_handle.Pass(), mojo::String("*")); |
| 156 trace_collector_.reset(new TraceCollector(pipe.consumer_handle.Pass())); | 152 trace_collector_.reset(new TraceCollector(pipe.consumer_handle.Pass())); |
| 157 Respond(connection_id, "Starting trace (type 'stop_tracing' to stop)\n"); | 153 Respond(callback, "Starting trace (type 'stop_tracing' to stop)\n"); |
| 158 } | 154 } |
| 159 | 155 |
| 160 void StopTracing(int connection_id) { | 156 void StopTracing(const HttpResponseCallback& callback) { |
| 161 if (!is_tracing_) { | 157 if (!is_tracing_) { |
| 162 Error(connection_id, "Not tracing yet. Use start_tracing to start.\n"); | 158 Error(callback, "Not tracing yet. Use start_tracing to start.\n"); |
| 163 return; | 159 return; |
| 164 } | 160 } |
| 165 | 161 |
| 166 is_tracing_ = false; | 162 is_tracing_ = false; |
| 167 tracing_->StopAndFlush(); | 163 tracing_->StopAndFlush(); |
| 168 trace_collector_->GetTrace(base::Bind( | 164 trace_collector_->GetTrace(base::Bind(&SkyDebugger::OnTraceAvailable, |
| 169 &SkyDebugger::OnTraceAvailable, base::Unretained(this), connection_id)); | 165 base::Unretained(this), callback)); |
| 170 } | 166 } |
| 171 | 167 |
| 172 void OnTraceAvailable(int connection_id, std::string trace) { | 168 void OnTraceAvailable(HttpResponseCallback callback, std::string trace) { |
| 173 trace_collector_.reset(); | 169 trace_collector_.reset(); |
| 174 Respond(connection_id, trace); | 170 Respond(callback, trace); |
| 175 } | 171 } |
| 176 | 172 |
| 177 void StartProfiling(int connection_id) { | 173 void StartProfiling(const HttpResponseCallback& callback) { |
| 178 #if !defined(NDEBUG) || !defined(ENABLE_PROFILING) | 174 #if !defined(NDEBUG) || !defined(ENABLE_PROFILING) |
| 179 Error(connection_id, | 175 Error(callback, |
| 180 "Profiling requires is_debug=false and enable_profiling=true"); | 176 "Profiling requires is_debug=false and enable_profiling=true"); |
| 181 return; | 177 return; |
| 182 #else | 178 #else |
| 183 base::debug::StartProfiling("sky_viewer.pprof"); | 179 base::debug::StartProfiling("sky_viewer.pprof"); |
| 184 Respond(connection_id, "Starting profiling (stop with 'stop_profiling')"); | 180 Respond(callback, "Starting profiling (stop with 'stop_profiling')"); |
| 185 #endif | 181 #endif |
| 186 } | 182 } |
| 187 | 183 |
| 188 void StopProfiling(int connection_id) { | 184 void StopProfiling(const HttpResponseCallback& callback) { |
| 189 if (!base::debug::BeingProfiled()) { | 185 if (!base::debug::BeingProfiled()) { |
| 190 Error(connection_id, "Profiling not started"); | 186 Error(callback, "Profiling not started"); |
| 191 return; | 187 return; |
| 192 } | 188 } |
| 193 base::debug::StopProfiling(); | 189 base::debug::StopProfiling(); |
| 194 Respond(connection_id, "Stopped profiling"); | 190 Respond(callback, "Stopped profiling"); |
| 195 } | 191 } |
| 196 | 192 |
| 197 bool is_tracing_; | 193 bool is_tracing_; |
| 198 mojo::WindowManagerPtr window_manager_; | 194 mojo::WindowManagerPtr window_manager_; |
| 199 tracing::TraceCoordinatorPtr tracing_; | 195 tracing::TraceCoordinatorPtr tracing_; |
| 200 std::string url_; | 196 std::string url_; |
| 201 scoped_ptr<net::HttpServer> web_server_; | |
| 202 uint32_t command_port_; | 197 uint32_t command_port_; |
| 203 | 198 |
| 199 http_server::HttpServerPtr http_server_; | |
| 200 | |
| 204 scoped_ptr<TraceCollector> trace_collector_; | 201 scoped_ptr<TraceCollector> trace_collector_; |
| 205 | 202 |
| 206 DISALLOW_COPY_AND_ASSIGN(SkyDebugger); | 203 DISALLOW_COPY_AND_ASSIGN(SkyDebugger); |
| 207 }; | 204 }; |
| 208 | 205 |
| 209 } // namespace debugger | 206 } // namespace debugger |
| 210 } // namespace sky | 207 } // namespace sky |
| 211 | 208 |
| 212 MojoResult MojoMain(MojoHandle shell_handle) { | 209 MojoResult MojoMain(MojoHandle shell_handle) { |
| 213 mojo::ApplicationRunnerChromium runner(new sky::debugger::SkyDebugger); | 210 mojo::ApplicationRunnerChromium runner(new sky::debugger::SkyDebugger); |
| 214 runner.set_message_loop_type(base::MessageLoop::TYPE_IO); | 211 runner.set_message_loop_type(base::MessageLoop::TYPE_IO); |
| 215 return runner.Run(shell_handle); | 212 return runner.Run(shell_handle); |
| 216 } | 213 } |
| OLD | NEW |