Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / devtools / device / android_device_manager.cc
blob3426726d31ab2d817d8ac713dd69d3634466132d
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
3 // found in the LICENSE file.
5 #include "chrome/browser/devtools/device/android_device_manager.h"
7 #include <string.h>
9 #include "base/location.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/socket/stream_socket.h"
18 using content::BrowserThread;
20 namespace {
22 const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread";
24 const int kBufferSize = 16 * 1024;
26 static const char kModelOffline[] = "Offline";
28 static const char kHttpGetRequest[] = "GET %s HTTP/1.1\r\n\r\n";
30 static const char kWebSocketUpgradeRequest[] = "GET %s HTTP/1.1\r\n"
31 "Upgrade: WebSocket\r\n"
32 "Connection: Upgrade\r\n"
33 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
34 "Sec-WebSocket-Version: 13\r\n"
35 "%s"
36 "\r\n";
38 static void PostDeviceInfoCallback(
39 scoped_refptr<base::SingleThreadTaskRunner> response_task_runner,
40 const AndroidDeviceManager::DeviceInfoCallback& callback,
41 const AndroidDeviceManager::DeviceInfo& device_info) {
42 response_task_runner->PostTask(FROM_HERE, base::Bind(callback, device_info));
45 static void PostCommandCallback(
46 scoped_refptr<base::SingleThreadTaskRunner> response_task_runner,
47 const AndroidDeviceManager::CommandCallback& callback,
48 int result,
49 const std::string& response) {
50 response_task_runner->PostTask(FROM_HERE,
51 base::Bind(callback, result, response));
54 static void PostHttpUpgradeCallback(
55 scoped_refptr<base::SingleThreadTaskRunner> response_task_runner,
56 const AndroidDeviceManager::HttpUpgradeCallback& callback,
57 int result,
58 const std::string& extensions,
59 const std::string& body_head,
60 scoped_ptr<net::StreamSocket> socket) {
61 response_task_runner->PostTask(
62 FROM_HERE, base::Bind(callback, result, extensions, body_head,
63 base::Passed(&socket)));
66 class HttpRequest {
67 public:
68 typedef AndroidDeviceManager::CommandCallback CommandCallback;
69 typedef AndroidDeviceManager::HttpUpgradeCallback HttpUpgradeCallback;
71 static void CommandRequest(const std::string& request,
72 const CommandCallback& callback,
73 int result,
74 scoped_ptr<net::StreamSocket> socket) {
75 if (result != net::OK) {
76 callback.Run(result, std::string());
77 return;
79 new HttpRequest(socket.Pass(), request, callback);
82 static void HttpUpgradeRequest(const std::string& request,
83 const HttpUpgradeCallback& callback,
84 int result,
85 scoped_ptr<net::StreamSocket> socket) {
86 if (result != net::OK) {
87 callback.Run(
88 result, std::string(), std::string(),
89 make_scoped_ptr<net::StreamSocket>(nullptr));
90 return;
92 new HttpRequest(socket.Pass(), request, callback);
95 private:
96 HttpRequest(scoped_ptr<net::StreamSocket> socket,
97 const std::string& request,
98 const CommandCallback& callback)
99 : socket_(socket.Pass()),
100 command_callback_(callback),
101 expected_size_(-1),
102 header_size_(0) {
103 SendRequest(request);
106 HttpRequest(scoped_ptr<net::StreamSocket> socket,
107 const std::string& request,
108 const HttpUpgradeCallback& callback)
109 : socket_(socket.Pass()),
110 http_upgrade_callback_(callback),
111 expected_size_(-1),
112 header_size_(0) {
113 SendRequest(request);
116 ~HttpRequest() {
119 void DoSendRequest(int result) {
120 while (result != net::ERR_IO_PENDING) {
121 if (!CheckNetResultOrDie(result))
122 return;
124 if (result > 0)
125 request_->DidConsume(result);
127 if (request_->BytesRemaining() == 0) {
128 request_ = nullptr;
129 ReadResponse(net::OK);
130 return;
133 result = socket_->Write(
134 request_.get(),
135 request_->BytesRemaining(),
136 base::Bind(&HttpRequest::DoSendRequest, base::Unretained(this)));
140 void SendRequest(const std::string& request) {
141 scoped_refptr<net::IOBuffer> base_buffer =
142 new net::IOBuffer(request.size());
143 memcpy(base_buffer->data(), request.data(), request.size());
144 request_ = new net::DrainableIOBuffer(base_buffer.get(), request.size());
146 DoSendRequest(net::OK);
149 void ReadResponse(int result) {
150 if (!CheckNetResultOrDie(result))
151 return;
153 response_buffer_ = new net::IOBuffer(kBufferSize);
155 result = socket_->Read(
156 response_buffer_.get(),
157 kBufferSize,
158 base::Bind(&HttpRequest::OnResponseData, base::Unretained(this)));
159 if (result != net::ERR_IO_PENDING)
160 OnResponseData(result);
163 void OnResponseData(int result) {
164 if (!CheckNetResultOrDie(result))
165 return;
166 if (result == 0) {
167 CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED);
168 return;
171 response_.append(response_buffer_->data(), result);
172 if (expected_size_ < 0) {
173 int expected_length = 0;
175 // TODO(kaznacheev): Use net::HttpResponseHeader to parse the header.
176 std::string content_length = ExtractHeader("Content-Length:");
177 if (!content_length.empty()) {
178 if (!base::StringToInt(content_length, &expected_length)) {
179 CheckNetResultOrDie(net::ERR_FAILED);
180 return;
184 header_size_ = response_.find("\r\n\r\n");
185 if (header_size_ != std::string::npos) {
186 header_size_ += 4;
187 expected_size_ = header_size_ + expected_length;
191 // WebSocket handshake doesn't contain the Content-Length. For this case,
192 // |expected_size_| is set to the size of the header (handshake).
193 // Some WebSocket frames can be already received into |response_|.
194 if (static_cast<int>(response_.length()) >= expected_size_) {
195 const std::string& body = response_.substr(header_size_);
196 if (!command_callback_.is_null()) {
197 command_callback_.Run(net::OK, body);
198 } else {
199 // Pass the WebSocket frames (in |body|), too.
200 http_upgrade_callback_.Run(net::OK,
201 ExtractHeader("Sec-WebSocket-Extensions:"), body, socket_.Pass());
203 delete this;
204 return;
207 result = socket_->Read(
208 response_buffer_.get(),
209 kBufferSize,
210 base::Bind(&HttpRequest::OnResponseData, base::Unretained(this)));
211 if (result != net::ERR_IO_PENDING)
212 OnResponseData(result);
215 std::string ExtractHeader(const std::string& header) {
216 size_t start_pos = response_.find(header);
217 if (start_pos == std::string::npos)
218 return std::string();
220 size_t endline_pos = response_.find("\n", start_pos);
221 if (endline_pos == std::string::npos)
222 return std::string();
224 std::string value = response_.substr(
225 start_pos + header.length(), endline_pos - start_pos - header.length());
226 base::TrimWhitespace(value, base::TRIM_ALL, &value);
227 return value;
230 bool CheckNetResultOrDie(int result) {
231 if (result >= 0)
232 return true;
233 if (!command_callback_.is_null()) {
234 command_callback_.Run(result, std::string());
235 } else {
236 http_upgrade_callback_.Run(
237 result, std::string(), std::string(),
238 make_scoped_ptr<net::StreamSocket>(nullptr));
240 delete this;
241 return false;
244 scoped_ptr<net::StreamSocket> socket_;
245 scoped_refptr<net::DrainableIOBuffer> request_;
246 std::string response_;
247 CommandCallback command_callback_;
248 HttpUpgradeCallback http_upgrade_callback_;
250 scoped_refptr<net::IOBuffer> response_buffer_;
251 // Initially -1. Once the end of the header is seen:
252 // - If the Content-Length header is included, this variable is set to the
253 // sum of the header size (including the last two CRLFs) and the value of
254 // the header.
255 // - Otherwise, this variable is set to the size of the header (including the
256 // last two CRLFs).
257 int expected_size_;
258 // Set to the size of the header part in |response_|.
259 size_t header_size_;
262 class DevicesRequest : public base::RefCountedThreadSafe<DevicesRequest> {
263 public:
264 typedef AndroidDeviceManager::DeviceInfo DeviceInfo;
265 typedef AndroidDeviceManager::DeviceProvider DeviceProvider;
266 typedef AndroidDeviceManager::DeviceProviders DeviceProviders;
267 typedef AndroidDeviceManager::DeviceDescriptors DeviceDescriptors;
268 typedef base::Callback<void(scoped_ptr<DeviceDescriptors>)>
269 DescriptorsCallback;
271 static void Start(
272 scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
273 const DeviceProviders& providers,
274 const DescriptorsCallback& callback) {
275 // Don't keep counted reference on calling thread;
276 DevicesRequest* request = new DevicesRequest(callback);
277 // Avoid destruction while sending requests
278 request->AddRef();
279 for (DeviceProviders::const_iterator it = providers.begin();
280 it != providers.end(); ++it) {
281 device_task_runner->PostTask(
282 FROM_HERE, base::Bind(&DeviceProvider::QueryDevices, *it,
283 base::Bind(&DevicesRequest::ProcessSerials,
284 request, *it)));
286 device_task_runner->ReleaseSoon(FROM_HERE, request);
289 private:
290 explicit DevicesRequest(const DescriptorsCallback& callback)
291 : response_task_runner_(base::ThreadTaskRunnerHandle::Get()),
292 callback_(callback),
293 descriptors_(new DeviceDescriptors()) {}
295 friend class base::RefCountedThreadSafe<DevicesRequest>;
296 ~DevicesRequest() {
297 response_task_runner_->PostTask(
298 FROM_HERE, base::Bind(callback_, base::Passed(&descriptors_)));
301 typedef std::vector<std::string> Serials;
303 void ProcessSerials(scoped_refptr<DeviceProvider> provider,
304 const Serials& serials) {
305 for (Serials::const_iterator it = serials.begin(); it != serials.end();
306 ++it) {
307 descriptors_->resize(descriptors_->size() + 1);
308 descriptors_->back().provider = provider;
309 descriptors_->back().serial = *it;
313 scoped_refptr<base::SingleThreadTaskRunner> response_task_runner_;
314 DescriptorsCallback callback_;
315 scoped_ptr<DeviceDescriptors> descriptors_;
318 void ReleaseDeviceAndProvider(
319 AndroidDeviceManager::DeviceProvider* provider,
320 const std::string& serial) {
321 provider->ReleaseDevice(serial);
322 provider->Release();
325 } // namespace
327 AndroidDeviceManager::BrowserInfo::BrowserInfo()
328 : type(kTypeOther) {
331 AndroidDeviceManager::DeviceInfo::DeviceInfo()
332 : model(kModelOffline), connected(false) {
335 AndroidDeviceManager::DeviceInfo::~DeviceInfo() {
338 AndroidDeviceManager::DeviceDescriptor::DeviceDescriptor() {
341 AndroidDeviceManager::DeviceDescriptor::~DeviceDescriptor() {
344 void AndroidDeviceManager::DeviceProvider::SendJsonRequest(
345 const std::string& serial,
346 const std::string& socket_name,
347 const std::string& request,
348 const CommandCallback& callback) {
349 OpenSocket(serial,
350 socket_name,
351 base::Bind(&HttpRequest::CommandRequest,
352 base::StringPrintf(kHttpGetRequest, request.c_str()),
353 callback));
356 void AndroidDeviceManager::DeviceProvider::HttpUpgrade(
357 const std::string& serial,
358 const std::string& socket_name,
359 const std::string& path,
360 const std::string& extensions,
361 const HttpUpgradeCallback& callback) {
362 std::string extensions_with_new_line =
363 extensions.empty() ? std::string() : extensions + "\r\n";
364 OpenSocket(
365 serial,
366 socket_name,
367 base::Bind(&HttpRequest::HttpUpgradeRequest,
368 base::StringPrintf(kWebSocketUpgradeRequest,
369 path.c_str(),
370 extensions_with_new_line.c_str()),
371 callback));
374 void AndroidDeviceManager::DeviceProvider::ReleaseDevice(
375 const std::string& serial) {
378 AndroidDeviceManager::DeviceProvider::DeviceProvider() {
381 AndroidDeviceManager::DeviceProvider::~DeviceProvider() {
384 void AndroidDeviceManager::Device::QueryDeviceInfo(
385 const DeviceInfoCallback& callback) {
386 task_runner_->PostTask(
387 FROM_HERE,
388 base::Bind(&DeviceProvider::QueryDeviceInfo, provider_, serial_,
389 base::Bind(&PostDeviceInfoCallback,
390 base::ThreadTaskRunnerHandle::Get(), callback)));
393 void AndroidDeviceManager::Device::OpenSocket(const std::string& socket_name,
394 const SocketCallback& callback) {
395 task_runner_->PostTask(
396 FROM_HERE, base::Bind(&DeviceProvider::OpenSocket, provider_, serial_,
397 socket_name, callback));
400 void AndroidDeviceManager::Device::SendJsonRequest(
401 const std::string& socket_name,
402 const std::string& request,
403 const CommandCallback& callback) {
404 task_runner_->PostTask(
405 FROM_HERE,
406 base::Bind(&DeviceProvider::SendJsonRequest, provider_, serial_,
407 socket_name, request,
408 base::Bind(&PostCommandCallback,
409 base::ThreadTaskRunnerHandle::Get(), callback)));
412 void AndroidDeviceManager::Device::HttpUpgrade(
413 const std::string& socket_name,
414 const std::string& path,
415 const std::string& extensions,
416 const HttpUpgradeCallback& callback) {
417 task_runner_->PostTask(
418 FROM_HERE,
419 base::Bind(&DeviceProvider::HttpUpgrade, provider_, serial_, socket_name,
420 path, extensions,
421 base::Bind(&PostHttpUpgradeCallback,
422 base::ThreadTaskRunnerHandle::Get(), callback)));
425 AndroidDeviceManager::Device::Device(
426 scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
427 scoped_refptr<DeviceProvider> provider,
428 const std::string& serial)
429 : task_runner_(device_task_runner),
430 provider_(provider),
431 serial_(serial),
432 weak_factory_(this) {
435 AndroidDeviceManager::Device::~Device() {
436 std::set<AndroidWebSocket*> sockets_copy(sockets_);
437 for (AndroidWebSocket* socket : sockets_copy)
438 socket->OnSocketClosed();
440 provider_->AddRef();
441 DeviceProvider* raw_ptr = provider_.get();
442 provider_ = NULL;
443 task_runner_->PostTask(FROM_HERE,
444 base::Bind(&ReleaseDeviceAndProvider,
445 base::Unretained(raw_ptr), serial_));
448 AndroidDeviceManager::HandlerThread*
449 AndroidDeviceManager::HandlerThread::instance_ = NULL;
451 // static
452 scoped_refptr<AndroidDeviceManager::HandlerThread>
453 AndroidDeviceManager::HandlerThread::GetInstance() {
454 DCHECK_CURRENTLY_ON(BrowserThread::UI);
455 if (!instance_)
456 new HandlerThread();
457 return instance_;
460 AndroidDeviceManager::HandlerThread::HandlerThread() {
461 DCHECK_CURRENTLY_ON(BrowserThread::UI);
462 instance_ = this;
463 thread_ = new base::Thread(kDevToolsAdbBridgeThreadName);
464 base::Thread::Options options;
465 options.message_loop_type = base::MessageLoop::TYPE_IO;
466 if (!thread_->StartWithOptions(options)) {
467 delete thread_;
468 thread_ = NULL;
472 scoped_refptr<base::SingleThreadTaskRunner>
473 AndroidDeviceManager::HandlerThread::message_loop() {
474 return thread_ ? thread_->task_runner() : NULL;
477 // static
478 void AndroidDeviceManager::HandlerThread::StopThread(
479 base::Thread* thread) {
480 thread->Stop();
483 AndroidDeviceManager::HandlerThread::~HandlerThread() {
484 DCHECK_CURRENTLY_ON(BrowserThread::UI);
485 instance_ = NULL;
486 if (!thread_)
487 return;
488 // Shut down thread on FILE thread to join into IO.
489 content::BrowserThread::PostTask(
490 content::BrowserThread::FILE, FROM_HERE,
491 base::Bind(&HandlerThread::StopThread, thread_));
494 // static
495 scoped_ptr<AndroidDeviceManager> AndroidDeviceManager::Create() {
496 return make_scoped_ptr(new AndroidDeviceManager());
499 void AndroidDeviceManager::SetDeviceProviders(
500 const DeviceProviders& providers) {
501 for (DeviceProviders::iterator it = providers_.begin();
502 it != providers_.end(); ++it) {
503 (*it)->AddRef();
504 DeviceProvider* raw_ptr = it->get();
505 *it = NULL;
506 handler_thread_->message_loop()->ReleaseSoon(FROM_HERE, raw_ptr);
508 providers_ = providers;
511 void AndroidDeviceManager::QueryDevices(const DevicesCallback& callback) {
512 DevicesRequest::Start(handler_thread_->message_loop(), providers_,
513 base::Bind(&AndroidDeviceManager::UpdateDevices,
514 weak_factory_.GetWeakPtr(), callback));
517 AndroidDeviceManager::AndroidDeviceManager()
518 : handler_thread_(HandlerThread::GetInstance()),
519 weak_factory_(this) {
522 AndroidDeviceManager::~AndroidDeviceManager() {
523 SetDeviceProviders(DeviceProviders());
526 void AndroidDeviceManager::UpdateDevices(
527 const DevicesCallback& callback,
528 scoped_ptr<DeviceDescriptors> descriptors) {
529 Devices response;
530 DeviceWeakMap new_devices;
531 for (DeviceDescriptors::const_iterator it = descriptors->begin();
532 it != descriptors->end();
533 ++it) {
534 DeviceWeakMap::iterator found = devices_.find(it->serial);
535 scoped_refptr<Device> device;
536 if (found == devices_.end() || !found->second ||
537 found->second->provider_.get() != it->provider.get()) {
538 device =
539 new Device(handler_thread_->message_loop(), it->provider, it->serial);
540 } else {
541 device = found->second.get();
543 response.push_back(device);
544 new_devices[it->serial] = device->weak_factory_.GetWeakPtr();
546 devices_.swap(new_devices);
547 callback.Run(response);