Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(524)

Side by Side Diff: chrome/browser/devtools/devtools_adb_bridge.cc

Issue 12586010: DevTools: extract ADB command classes, change objects' lifetimes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Win build fixed. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "chrome/browser/devtools/devtools_adb_bridge.h" 5 #include "chrome/browser/devtools/devtools_adb_bridge.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop_proxy.h" 13 #include "base/message_loop_proxy.h"
14 #include "base/string_util.h" 14 #include "base/string_util.h"
15 #include "base/stringprintf.h" 15 #include "base/stringprintf.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/threading/thread.h" 17 #include "base/threading/thread.h"
18 #include "base/values.h" 18 #include "base/values.h"
19 #include "chrome/browser/devtools/adb_client_socket.h" 19 #include "chrome/browser/devtools/adb_client_socket.h"
20 #include "chrome/browser/profiles/profile.h"
20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/devtools_agent_host.h"
23 #include "content/public/browser/devtools_client_host.h"
24 #include "content/public/browser/devtools_manager.h"
21 #include "net/base/net_errors.h" 25 #include "net/base/net_errors.h"
26 #include "net/server/web_socket.h"
22 27
23 using content::BrowserThread; 28 using content::BrowserThread;
29 using net::WebSocket;
24 30
25 namespace { 31 namespace {
26 32
27 static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread"; 33 static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread";
28 static const char kDevToolsChannelName[] = "chrome_devtools_remote"; 34 static const char kDevToolsChannelName[] = "chrome_devtools_remote";
29 static const char kHostDevicesCommand[] = "host:devices"; 35 static const char kHostDevicesCommand[] = "host:devices";
30 static const char kDeviceModelCommand[] = 36 static const char kDeviceModelCommand[] =
31 "host:transport:%s|shell:getprop ro.product.model"; 37 "host:transport:%s|shell:getprop ro.product.model";
32 static const char kPageListQuery[] = "/json"; 38
39 static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
40 static const char kWebSocketUpgradeRequest[] = "GET %s HTTP/1.1\r\n"
41 "Upgrade: WebSocket\r\n"
42 "Connection: Upgrade\r\n"
43 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
44 "Sec-WebSocket-Version: 13\r\n"
45 "\r\n";
33 const int kAdbPort = 5037; 46 const int kAdbPort = 5037;
47 const int kBufferSize = 16 * 1024;
48
49 typedef DevToolsAdbBridge::Callback Callback;
50 typedef DevToolsAdbBridge::PagesCallback PagesCallback;
51
52 class AdbQueryCommand : public base::RefCounted<AdbQueryCommand> {
53 public:
54 AdbQueryCommand(const std::string& query,
55 const Callback& callback)
56 : query_(query),
57 callback_(callback) {
58 }
59
60 void Run() {
61 AdbClientSocket::AdbQuery(kAdbPort, query_,
62 base::Bind(&AdbQueryCommand::Handle, this));
63 }
64
65 private:
66 friend class base::RefCounted<AdbQueryCommand>;
67 virtual ~AdbQueryCommand() {}
68
69 void Handle(int result, const std::string& response) {
70 BrowserThread::PostTask(
71 BrowserThread::UI, FROM_HERE,
72 base::Bind(&AdbQueryCommand::Respond, this, result, response));
73 }
74
75 void Respond(int result, const std::string& response) {
76 callback_.Run(result, response);
77 }
78
79 std::string query_;
80 Callback callback_;
81 };
82
83 class AdbPagesCommand : public base::RefCounted<AdbPagesCommand> {
84 public:
85 explicit AdbPagesCommand(const PagesCallback& callback)
86 : callback_(callback) {
87 pages_.reset(new DevToolsAdbBridge::RemotePages());
88 }
89
90 void Run() {
91 AdbClientSocket::AdbQuery(
92 kAdbPort, kHostDevicesCommand,
93 base::Bind(&AdbPagesCommand::ReceivedDevices, this));
94 }
95
96 private:
97 friend class base::RefCounted<AdbPagesCommand>;
98 virtual ~AdbPagesCommand() {}
99
100 void ReceivedDevices(int result, const std::string& response) {
101 if (result != net::OK) {
102 ProcessSerials();
103 return;
104 }
105
106 std::vector<std::string> devices;
107 Tokenize(response, "\n", &devices);
108 for (size_t i = 0; i < devices.size(); ++i) {
109 std::vector<std::string> tokens;
110 Tokenize(devices[i], "\t ", &tokens);
111 std::string serial = tokens[0];
112 serials_.push_back(serial);
113 }
114
115 ProcessSerials();
116 }
117
118 void ProcessSerials() {
119 if (serials_.size() == 0) {
120 BrowserThread::PostTask(
121 BrowserThread::UI, FROM_HERE,
122 base::Bind(&AdbPagesCommand::Respond, this));
123 return;
124 }
125
126 AdbClientSocket::AdbQuery(
127 kAdbPort,
128 base::StringPrintf(kDeviceModelCommand, serials_.back().c_str()),
129 base::Bind(&AdbPagesCommand::ReceivedModel, this));
130 }
131
132 void ReceivedModel(int result, const std::string& response) {
133 if (result != net::OK) {
134 serials_.pop_back();
135 ProcessSerials();
136 return;
137 }
138
139 AdbClientSocket::HttpQuery(
140 kAdbPort, serials_.back(), kDevToolsChannelName, kPageListRequest,
141 base::Bind(&AdbPagesCommand::ReceivedPages, this, response));
142 }
143
144 void ReceivedPages(const std::string& model,
145 int result,
146 const std::string& response) {
147 std::string serial = serials_.back();
148 serials_.pop_back();
149 if (result < 0) {
150 ProcessSerials();
151 return;
152 }
153
154 std::string body = response.substr(result);
155 scoped_ptr<base::Value> value(base::JSONReader::Read(body));
156 base::ListValue* list_value;
157 if (!value || !value->GetAsList(&list_value)) {
158 ProcessSerials();
159 return;
160 }
161
162 base::Value* item;
163 for (size_t i = 0; i < list_value->GetSize(); ++i) {
164 list_value->Get(i, &item);
165 base::DictionaryValue* dict;
166 if (!item || !item->GetAsDictionary(&dict))
167 continue;
168 pages_->push_back(
169 new DevToolsAdbBridge::RemotePage(serial, model, *dict));
170 }
171 ProcessSerials();
172 }
173
174 void Respond() {
175 callback_.Run(net::OK, pages_.release());
176 }
177
178 PagesCallback callback_;
179 std::vector<std::string> serials_;
180 scoped_ptr<DevToolsAdbBridge::RemotePages> pages_;
181 };
182
183 class AdbAttachCommand : public base::RefCounted<AdbAttachCommand> {
184 public:
185 explicit AdbAttachCommand(scoped_refptr<DevToolsAdbBridge::RemotePage> page)
186 : page_(page) {
187 }
188
189 void Run() {
190 AdbClientSocket::HttpQuery(
191 kAdbPort, page_->serial(), kDevToolsChannelName,
192 base::StringPrintf(kWebSocketUpgradeRequest,
193 page_->debug_url().c_str()),
194 base::Bind(&AdbAttachCommand::Handle, this));
195 }
196
197 private:
198 friend class base::RefCounted<AdbAttachCommand>;
199 virtual ~AdbAttachCommand() {}
200
201 void Handle(int result, net::TCPClientSocket* socket) {
202 if (result != net::OK || socket == NULL)
203 return;
204
205 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
206 base::Bind(&AdbAttachCommand::OpenDevToolsWindow, this, socket));
207 }
208
209 void OpenDevToolsWindow(net::TCPClientSocket* socket) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 scoped_ptr<net::TCPClientSocket> tcp_socket(socket);
212 // TODO(pfeldman): Show DevToolsWindow here.
213 }
214
215 scoped_refptr<DevToolsAdbBridge::RemotePage> page_;
216 };
34 217
35 } // namespace 218 } // namespace
36 219
37 DevToolsAdbBridge::AgentHost::AgentHost(const std::string& serial, 220 DevToolsAdbBridge::RemotePage::RemotePage(const std::string& serial,
38 const std::string& model, 221 const std::string& model,
39 const base::DictionaryValue& value) 222 const base::DictionaryValue& value)
40 : serial_(serial), 223 : serial_(serial),
41 model_(model) { 224 model_(model) {
42 value.GetString("id", &id_); 225 value.GetString("id", &id_);
226 value.GetString("url", &url_);
43 value.GetString("title", &title_); 227 value.GetString("title", &title_);
44 value.GetString("descirption", &description_); 228 value.GetString("descirption", &description_);
45 value.GetString("faviconUrl", &favicon_url_); 229 value.GetString("faviconUrl", &favicon_url_);
46 value.GetString("webSocketDebuggerUrl", &debug_url_); 230 value.GetString("webSocketDebuggerUrl", &debug_url_);
47 } 231 value.GetString("devtoolsFrontendUrl", &frontend_url_);
48 232
49 DevToolsAdbBridge::AgentHost::~AgentHost() { 233 if (debug_url_.find("ws://") == 0)
50 } 234 debug_url_ = debug_url_.substr(5);
235 else
236 debug_url_ = "";
237
238 size_t ws_param = frontend_url_.find("?ws");
239 if (ws_param != std::string::npos)
240 frontend_url_ = frontend_url_.substr(0, ws_param);
241 }
242
243 DevToolsAdbBridge::RemotePage::~RemotePage() {
244 }
245
246 DevToolsAdbBridge::RefCountedAdbThread*
247 DevToolsAdbBridge::RefCountedAdbThread::instance_ = NULL;
51 248
52 // static 249 // static
53 DevToolsAdbBridge* DevToolsAdbBridge::Start() { 250 scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread>
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 251 DevToolsAdbBridge::RefCountedAdbThread::GetInstance() {
55 return new DevToolsAdbBridge(); 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
56 } 253 if (!instance_)
57 254 new RefCountedAdbThread();
58 void DevToolsAdbBridge::Stop() { 255 return instance_;
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 256 }
60 if (!thread_.get()) { 257
61 ResetHandlerAndReleaseOnUIThread(); 258 DevToolsAdbBridge::RefCountedAdbThread::RefCountedAdbThread() {
62 return; 259 instance_ = this;
63 } 260 thread_ = new base::Thread(kDevToolsAdbBridgeThreadName);
64 BrowserThread::PostTaskAndReply( 261 base::Thread::Options options;
262 options.message_loop_type = MessageLoop::TYPE_IO;
263 if (!thread_->StartWithOptions(options)) {
264 delete thread_;
265 thread_ = NULL;
266 }
267 }
268
269 MessageLoop* DevToolsAdbBridge::RefCountedAdbThread::message_loop() {
270 return thread_ ? thread_->message_loop() : NULL;
271 }
272
273 // static
274 void DevToolsAdbBridge::RefCountedAdbThread::StopThread(base::Thread* thread) {
275 thread->Stop();
276 }
277
278 DevToolsAdbBridge::RefCountedAdbThread::~RefCountedAdbThread() {
279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
280 instance_ = NULL;
281 if (!thread_)
282 return;
283 // Shut down thread on FILE thread to join into IO.
284 BrowserThread::PostTask(
65 BrowserThread::FILE, FROM_HERE, 285 BrowserThread::FILE, FROM_HERE,
66 base::Bind(&DevToolsAdbBridge::StopHandlerOnFileThread, 286 base::Bind(&RefCountedAdbThread::StopThread, thread_));
67 base::Unretained(this)), 287 }
68 base::Bind(&DevToolsAdbBridge::ResetHandlerAndReleaseOnUIThread, 288
69 base::Unretained(this))); 289 DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile)
290 : profile_(profile),
291 adb_thread_(RefCountedAdbThread::GetInstance()),
292 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
293 has_message_loop_(adb_thread_->message_loop() != NULL) {
294 }
295
296 DevToolsAdbBridge::~DevToolsAdbBridge() {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
70 } 298 }
71 299
72 void DevToolsAdbBridge::Query( 300 void DevToolsAdbBridge::Query(
73 const std::string query, 301 const std::string query,
74 const Callback& callback) { 302 const Callback& callback) {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76 304 if (!has_message_loop_) {
77 // There is a race condition in case Query immediately follows start. We 305 callback.Run(net::ERR_FAILED, "Could not start ADB thread");
78 // consider it Ok since query is polling anyways. 306 return;
79 if (!thread_.get()) { 307 }
80 callback.Run(net::ERR_FAILED, "ADB is not yet connected"); 308 scoped_refptr<AdbQueryCommand> command(new AdbQueryCommand(query, callback));
81 return; 309 adb_thread_->message_loop()->PostTask(FROM_HERE,
82 } 310 base::Bind(&AdbQueryCommand::Run, command));
83 thread_->message_loop()->PostTask( 311 }
312
313 void DevToolsAdbBridge::Pages(const PagesCallback& callback) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
315 if (!has_message_loop_)
316 return;
317
318 scoped_refptr<AdbPagesCommand> command(new AdbPagesCommand(callback));
319 adb_thread_->message_loop()->PostTask(FROM_HERE,
320 base::Bind(&AdbPagesCommand::Run, command));
321 }
322
323 void DevToolsAdbBridge::Attach(scoped_refptr<RemotePage> page) {
324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
325 if (!has_message_loop_)
326 return;
327
328 scoped_refptr<AdbAttachCommand> command(new AdbAttachCommand(page));
329 adb_thread_->message_loop()->PostTask(
84 FROM_HERE, 330 FROM_HERE,
85 base::Bind(&DevToolsAdbBridge::QueryOnHandlerThread, 331 base::Bind(&AdbAttachCommand::Run, command));
86 base::Unretained(this), query, callback)); 332 }
87 }
88
89 void DevToolsAdbBridge::Devices() {
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
91 if (!thread_.get())
92 return;
93
94 thread_->message_loop()->PostTask(
95 FROM_HERE,
96 base::Bind(&DevToolsAdbBridge::DevicesOnHandlerThread,
97 base::Unretained(this),
98 base::Bind(&DevToolsAdbBridge::PrintHosts,
99 base::Unretained(this))));
100 }
101
102 DevToolsAdbBridge::DevToolsAdbBridge() {
103 thread_.reset(new base::Thread(kDevToolsAdbBridgeThreadName));
104
105 base::Thread::Options options;
106 options.message_loop_type = MessageLoop::TYPE_IO;
107 if (!thread_->StartWithOptions(options))
108 thread_.reset();
109 }
110
111 DevToolsAdbBridge::~DevToolsAdbBridge() {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113 // Stop() must be called prior to destruction.
114 DCHECK(thread_.get() == NULL);
115 }
116
117 // Runs on FILE thread to make sure that it is serialized against
118 // {Start|Stop}HandlerThread and to allow calling pthread_join.
119 void DevToolsAdbBridge::StopHandlerOnFileThread() {
120 if (!thread_->message_loop())
121 return;
122 // Thread::Stop joins the thread.
123 thread_->Stop();
124 }
125
126 void DevToolsAdbBridge::ResetHandlerAndReleaseOnUIThread() {
127 ResetHandlerOnUIThread();
128 delete this;
129 }
130
131 void DevToolsAdbBridge::ResetHandlerOnUIThread() {
132 thread_.reset();
133 }
134
135 void DevToolsAdbBridge::QueryOnHandlerThread(
136 const std::string query,
137 const Callback& callback) {
138 AdbClientSocket::AdbQuery(kAdbPort, query,
139 base::Bind(&DevToolsAdbBridge::QueryResponseOnHandlerThread,
140 base::Unretained(this), callback));
141 }
142
143 void DevToolsAdbBridge::QueryResponseOnHandlerThread(
144 const Callback& callback,
145 int result,
146 const std::string& response) {
147 BrowserThread::PostTask(
148 BrowserThread::UI, FROM_HERE,
149 base::Bind(&DevToolsAdbBridge::RespondOnUIThread, base::Unretained(this),
150 callback, result, response));
151 }
152
153 void DevToolsAdbBridge::DevicesOnHandlerThread(
154 const HostsCallback& callback) {
155 AdbClientSocket::AdbQuery(
156 kAdbPort, kHostDevicesCommand,
157 base::Bind(&DevToolsAdbBridge::ReceivedDevices,
158 base::Unretained(this), callback));
159 }
160
161 void DevToolsAdbBridge::ReceivedDevices(
162 const HostsCallback& callback,
163 int result,
164 const std::string& response) {
165 AgentHosts* hosts = new AgentHosts();
166 if (result != net::OK) {
167 callback.Run(result, hosts);
168 return;
169 }
170
171 std::vector<std::string> devices;
172 Tokenize(response, "\n", &devices);
173 std::vector<std::string>* serials = new std::vector<std::string>();
174 for (size_t i = 0; i < devices.size(); ++i) {
175 std::vector<std::string> tokens;
176 Tokenize(devices[i], "\t ", &tokens);
177 std::string serial = tokens[0];
178 serials->push_back(serial);
179 }
180
181 ProcessSerials(callback, hosts, serials);
182 }
183
184 void DevToolsAdbBridge::ProcessSerials(
185 const HostsCallback& callback,
186 AgentHosts* hosts,
187 std::vector<std::string>* serials) {
188 if (serials->size() == 0) {
189 delete serials;
190 callback.Run(net::OK, hosts);
191 return;
192 }
193
194 AdbClientSocket::AdbQuery(
195 kAdbPort,
196 base::StringPrintf(kDeviceModelCommand, serials->back().c_str()),
197 base::Bind(&DevToolsAdbBridge::ReceivedModel, base::Unretained(this),
198 callback, hosts, serials));
199 }
200
201 void DevToolsAdbBridge::ReceivedModel(const HostsCallback& callback,
202 AgentHosts* hosts,
203 std::vector<std::string>* serials,
204 int result,
205 const std::string& response) {
206 if (result != net::OK) {
207 serials->pop_back();
208 ProcessSerials(callback, hosts, serials);
209 return;
210 }
211
212 AdbClientSocket::HttpQuery(
213 kAdbPort, serials->back(), kDevToolsChannelName, kPageListQuery,
214 base::Bind(&DevToolsAdbBridge::ReceivedPages, base::Unretained(this),
215 callback, hosts, serials, response));
216
217 }
218
219 void DevToolsAdbBridge::ReceivedPages(const HostsCallback& callback,
220 AgentHosts* hosts,
221 std::vector<std::string>* serials,
222 const std::string& model,
223 int result,
224 const std::string& response) {
225 std::string serial = serials->back();
226 serials->pop_back();
227 if (result != net::OK) {
228 ProcessSerials(callback, hosts, serials);
229 return;
230 }
231
232 scoped_ptr<base::Value> value(base::JSONReader::Read(response));
233 base::ListValue* list_value;
234 if (!value || !value->GetAsList(&list_value)) {
235 ProcessSerials(callback, hosts, serials);
236 return;
237 }
238
239 base::Value* item;
240 for (size_t i = 0; i < list_value->GetSize(); ++i) {
241 list_value->Get(i, &item);
242 base::DictionaryValue* dict;
243 if (!item || !item->GetAsDictionary(&dict))
244 continue;
245 scoped_refptr<AgentHost> host = new AgentHost(serial, model, *dict);
246 hosts->push_back(host);
247 }
248 ProcessSerials(callback, hosts, serials);
249 }
250
251 void DevToolsAdbBridge::RespondOnUIThread(const Callback& callback,
252 int result,
253 const std::string& response) {
254 callback.Run(result, response);
255 }
256
257 void DevToolsAdbBridge::PrintHosts(int result, AgentHosts* hosts) {
258 for (AgentHosts::iterator it = hosts->begin(); it != hosts->end(); ++it) {
259 AgentHost* host = it->get();
260 fprintf(stderr, "HOST %s %s %s %s %s %s %s\n", host->serial().c_str(),
261 host->model().c_str(), host->id().c_str(), host->title().c_str(),
262 host->description().c_str(), host->favicon_url().c_str(),
263 host->debug_url().c_str());
264 }
265 }
OLDNEW
« no previous file with comments | « chrome/browser/devtools/devtools_adb_bridge.h ('k') | chrome/browser/resources/inspect/inspect.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698