| Index: chrome/browser/devtools/devtools_adb_bridge.cc
|
| diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6ff63cca1882086f90c412587091a96e001bfe1b
|
| --- /dev/null
|
| +++ b/chrome/browser/devtools/devtools_adb_bridge.cc
|
| @@ -0,0 +1,213 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/devtools/devtools_adb_bridge.h"
|
| +
|
| +#include <algorithm>
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/logging.h"
|
| +#include "base/message_loop_proxy.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/threading/thread.h"
|
| +#include "chrome/browser/devtools/adb_client_socket.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
| +
|
| +using content::BrowserThread;
|
| +
|
| +namespace {
|
| +
|
| +static const char* kDevToolsAdbBridgeThreadName = "Chrome_DevToolsADBThread";
|
| +const int kAdbPort = 5037;
|
| +const int kBufferSize = 16 * 1024;
|
| +
|
| +} // namespace
|
| +
|
| +struct DevToolsAdbBridge::RequestInfo {
|
| + Callback callback;
|
| + scoped_refptr<net::IOBuffer> buffer;
|
| + std::string data;
|
| +};
|
| +
|
| +// static
|
| +DevToolsAdbBridge* DevToolsAdbBridge::Start(Profile* profile) {
|
| + return new DevToolsAdbBridge(profile);
|
| +}
|
| +
|
| +void DevToolsAdbBridge::Stop() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (!thread_.get())
|
| + return;
|
| + BrowserThread::PostTaskAndReply(
|
| + BrowserThread::FILE, FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::StopHandlerOnFileThread, this),
|
| + base::Bind(&DevToolsAdbBridge::ResetHandlerAndReleaseOnUIThread, this));
|
| +}
|
| +
|
| +void DevToolsAdbBridge::Query(
|
| + const std::string query,
|
| + const Callback& callback) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + // There is a race condition in case Query immediately follows start. We
|
| + // consider it Ok since query is polling anyways.
|
| + if (!thread_.get()) {
|
| + callback.Run("ADB is not yet connected", std::string());
|
| + return;
|
| + }
|
| + thread_->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::QueryOnHandlerThread,
|
| + this, query, callback));
|
| +}
|
| +
|
| +void DevToolsAdbBridge::Fetch(
|
| + const std::string url,
|
| + const Callback& callback) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + thread_->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::FetchOnHandlerThread,
|
| + this, url, callback));
|
| +}
|
| +
|
| +DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile)
|
| + : profile_(profile) {
|
| + // Balanced in ResetThreadAndRelease().
|
| + AddRef();
|
| +
|
| + thread_.reset(new base::Thread(kDevToolsAdbBridgeThreadName));
|
| + BrowserThread::PostTask(
|
| + BrowserThread::FILE, FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::StartHandlerOnFileThread, this));
|
| +}
|
| +
|
| +DevToolsAdbBridge::~DevToolsAdbBridge() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + // Stop() must be called prior to destruction.
|
| + DCHECK(thread_.get() == NULL);
|
| +}
|
| +
|
| +void DevToolsAdbBridge::StartHandlerOnFileThread() {
|
| + base::Thread::Options options;
|
| + options.message_loop_type = MessageLoop::TYPE_IO;
|
| + if (!thread_->StartWithOptions(options)) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::ResetHandlerOnUIThread, this));
|
| + return;
|
| + }
|
| +
|
| + thread_->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::InitOnHandlerThread, this));
|
| +}
|
| +
|
| +// Runs on FILE thread to make sure that it is serialized against
|
| +// {Start|Stop}HandlerThread and to allow calling pthread_join.
|
| +void DevToolsAdbBridge::StopHandlerOnFileThread() {
|
| + if (!thread_->message_loop())
|
| + return;
|
| + thread_->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::TeardownOnHandlerThread, this));
|
| + // Thread::Stop joins the thread.
|
| + thread_->Stop();
|
| +}
|
| +
|
| +void DevToolsAdbBridge::ResetHandlerAndReleaseOnUIThread() {
|
| + ResetHandlerOnUIThread();
|
| + Release();
|
| +}
|
| +
|
| +void DevToolsAdbBridge::ResetHandlerOnUIThread() {
|
| + thread_.reset();
|
| +}
|
| +
|
| +void DevToolsAdbBridge::InitOnHandlerThread() {
|
| +}
|
| +
|
| +void DevToolsAdbBridge::QueryOnHandlerThread(
|
| + const std::string query,
|
| + const Callback& callback) {
|
| + ADBClientSocket::Query(
|
| + kAdbPort, query,
|
| + base::Bind(&DevToolsAdbBridge::QueryResponseOnHandlerThread,
|
| + base::Unretained(this), callback));
|
| +}
|
| +
|
| +void DevToolsAdbBridge::FetchOnHandlerThread(
|
| + const std::string url,
|
| + const Callback& callback) {
|
| + net::URLRequestContext* context =
|
| + profile_->GetRequestContext()->GetURLRequestContext();
|
| + net::URLRequest* request = new net::URLRequest(GURL(url), this, context);
|
| + RequestInfo info;
|
| + info.callback = callback;
|
| + info.buffer = new net::IOBuffer(kBufferSize);
|
| + info.data = "";
|
| + request_info_[request] = info;
|
| + request->Start();
|
| +}
|
| +
|
| +void DevToolsAdbBridge::QueryResponseOnHandlerThread(
|
| + const Callback& callback,
|
| + const std::string& error,
|
| + const std::string& response) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::RespondOnUIThread, this,
|
| + callback, error, response));
|
| +}
|
| +
|
| +void DevToolsAdbBridge::TeardownOnHandlerThread() {
|
| +}
|
| +
|
| +void DevToolsAdbBridge::RespondOnUIThread(
|
| + const Callback& callback,
|
| + const std::string& error,
|
| + const std::string& response) {
|
| + callback.Run(error, response);
|
| +}
|
| +
|
| +// Called on the handler thread.
|
| +void DevToolsAdbBridge::OnResponseStarted(net::URLRequest* request) {
|
| + int bytes_read = 0;
|
| + // Some servers may treat HEAD requests as GET requests. To free up the
|
| + // network connection as soon as possible, signal that the request has
|
| + // completed immediately, without trying to read any data back (all we care
|
| + // about is the response code and headers, which we already have).
|
| + net::IOBuffer* buffer = request_info_[request].buffer.get();
|
| + if (request->status().is_success())
|
| + request->Read(buffer, kBufferSize, &bytes_read);
|
| + OnReadCompleted(request, bytes_read);
|
| +}
|
| +
|
| +// Called on the handler thread.
|
| +void DevToolsAdbBridge::OnReadCompleted(net::URLRequest* request,
|
| + int bytes_read) {
|
| + net::IOBuffer* buffer = request_info_[request].buffer.get();
|
| + do {
|
| + if (!request->status().is_success() || bytes_read <= 0)
|
| + break;
|
| + request_info_[request].data =
|
| + request_info_[request].data + std::string(buffer->data(), bytes_read);
|
| + } while (request->Read(buffer, kBufferSize, &bytes_read));
|
| +
|
| + // See comments re: HEAD requests in OnResponseStarted().
|
| + if (!request->status().is_io_pending()) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DevToolsAdbBridge::RespondOnUIThread, this,
|
| + request_info_[request].callback, "", request_info_[request].data));
|
| + request_info_.erase(request);
|
| + delete request;
|
| + }
|
| +}
|
|
|