1 // Copyright (c) 2012 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 "chrome/browser/android/dev_tools_server.h" 6 7 #include <pwd.h> 8 #include <cstring> 9 10 #include "base/android/jni_string.h" 11 #include "base/basictypes.h" 12 #include "base/bind.h" 13 #include "base/callback.h" 14 #include "base/command_line.h" 15 #include "base/compiler_specific.h" 16 #include "base/logging.h" 17 #include "base/strings/stringprintf.h" 18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/devtools/devtools_adb_bridge.h" 20 #include "chrome/browser/history/top_sites.h" 21 #include "chrome/browser/profiles/profile_manager.h" 22 #include "chrome/browser/ui/android/tab_model/tab_model.h" 23 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" 24 #include "content/public/browser/android/devtools_auth.h" 25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/devtools_http_handler.h" 27 #include "content/public/browser/devtools_http_handler_delegate.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/common/content_switches.h" 30 #include "content/public/common/url_constants.h" 31 #include "grit/devtools_discovery_page_resources.h" 32 #include "jni/DevToolsServer_jni.h" 33 #include "net/socket/unix_domain_socket_posix.h" 34 #include "net/url_request/url_request_context_getter.h" 35 #include "ui/base/resource/resource_bundle.h" 36 #include "webkit/common/user_agent/user_agent_util.h" 37 38 namespace { 39 40 const char kFrontEndURL[] = 41 "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html"; 42 const char kDefaultSocketNamePrefix[] = "chrome"; 43 const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d"; 44 45 // Delegate implementation for the devtools http handler on android. A new 46 // instance of this gets created each time devtools is enabled. 47 class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate { 48 public: 49 DevToolsServerDelegate() 50 : last_tethering_socket_(0) { 51 } 52 53 virtual std::string GetDiscoveryPageHTML() OVERRIDE { 54 // TopSites updates itself after a delay. Ask TopSites to update itself 55 // when we're about to show the remote debugging landing page. 56 content::BrowserThread::PostTask( 57 content::BrowserThread::UI, 58 FROM_HERE, 59 base::Bind(&DevToolsServerDelegate::PopulatePageThumbnails)); 60 return ResourceBundle::GetSharedInstance().GetRawDataResource( 61 IDR_DEVTOOLS_DISCOVERY_PAGE_HTML).as_string(); 62 } 63 64 virtual bool BundlesFrontendResources() OVERRIDE { 65 return false; 66 } 67 68 virtual base::FilePath GetDebugFrontendDir() OVERRIDE { 69 return base::FilePath(); 70 } 71 72 virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE { 73 Profile* profile = 74 ProfileManager::GetLastUsedProfile()->GetOriginalProfile(); 75 history::TopSites* top_sites = profile->GetTopSites(); 76 if (top_sites) { 77 scoped_refptr<base::RefCountedMemory> data; 78 if (top_sites->GetPageThumbnail(url, &data)) 79 return std::string(reinterpret_cast<const char*>(data->front()), 80 data->size()); 81 } 82 return ""; 83 } 84 85 virtual content::RenderViewHost* CreateNewTarget() OVERRIDE { 86 Profile* profile = 87 g_browser_process->profile_manager()->GetDefaultProfile(); 88 TabModel* tab_model = TabModelList::GetTabModelWithProfile(profile); 89 if (!tab_model) 90 return NULL; 91 content::WebContents* web_contents = 92 tab_model->CreateTabForTesting(GURL(content::kAboutBlankURL)); 93 if (!web_contents) 94 return NULL; 95 return web_contents->GetRenderViewHost(); 96 } 97 98 virtual TargetType GetTargetType(content::RenderViewHost*) OVERRIDE { 99 return kTargetTypeTab; 100 } 101 102 virtual std::string GetViewDescription(content::RenderViewHost*) OVERRIDE { 103 return ""; 104 } 105 106 virtual scoped_refptr<net::StreamListenSocket> CreateSocketForTethering( 107 net::StreamListenSocket::Delegate* delegate, 108 std::string* name) OVERRIDE { 109 *name = base::StringPrintf( 110 kTetheringSocketName, getpid(), ++last_tethering_socket_); 111 return net::UnixDomainSocket::CreateAndListenWithAbstractNamespace( 112 *name, 113 "", 114 delegate, 115 base::Bind(&content::CanUserConnectToDevTools)); 116 } 117 118 private: 119 static void PopulatePageThumbnails() { 120 Profile* profile = 121 ProfileManager::GetLastUsedProfile()->GetOriginalProfile(); 122 history::TopSites* top_sites = profile->GetTopSites(); 123 if (top_sites) 124 top_sites->SyncWithHistory(); 125 } 126 127 int last_tethering_socket_; 128 129 DISALLOW_COPY_AND_ASSIGN(DevToolsServerDelegate); 130 }; 131 132 } // namespace 133 134 DevToolsServer::DevToolsServer() 135 : socket_name_(base::StringPrintf(kDevToolsChannelNameFormat, 136 kDefaultSocketNamePrefix)), 137 protocol_handler_(NULL) { 138 // Override the default socket name if one is specified on the command line. 139 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 140 if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) { 141 socket_name_ = command_line.GetSwitchValueASCII( 142 switches::kRemoteDebuggingSocketName); 143 } 144 } 145 146 DevToolsServer::DevToolsServer(const std::string& socket_name_prefix) 147 : socket_name_(base::StringPrintf(kDevToolsChannelNameFormat, 148 socket_name_prefix.c_str())), 149 protocol_handler_(NULL) { 150 } 151 152 DevToolsServer::~DevToolsServer() { 153 Stop(); 154 } 155 156 void DevToolsServer::Start() { 157 if (protocol_handler_) 158 return; 159 160 protocol_handler_ = content::DevToolsHttpHandler::Start( 161 new net::UnixDomainSocketWithAbstractNamespaceFactory( 162 socket_name_, 163 base::StringPrintf("%s_%d", socket_name_.c_str(), getpid()), 164 base::Bind(&content::CanUserConnectToDevTools)), 165 base::StringPrintf(kFrontEndURL, 166 webkit_glue::GetWebKitRevision().c_str()), 167 new DevToolsServerDelegate()); 168 } 169 170 void DevToolsServer::Stop() { 171 if (!protocol_handler_) 172 return; 173 // Note that the call to Stop() below takes care of |protocol_handler_| 174 // deletion. 175 protocol_handler_->Stop(); 176 protocol_handler_ = NULL; 177 } 178 179 bool DevToolsServer::IsStarted() const { 180 return protocol_handler_; 181 } 182 183 bool RegisterDevToolsServer(JNIEnv* env) { 184 return RegisterNativesImpl(env); 185 } 186 187 static jint InitRemoteDebugging(JNIEnv* env, 188 jobject obj, 189 jstring socket_name_prefix) { 190 DevToolsServer* server = new DevToolsServer( 191 base::android::ConvertJavaStringToUTF8(env, socket_name_prefix)); 192 return reinterpret_cast<jint>(server); 193 } 194 195 static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jint server) { 196 delete reinterpret_cast<DevToolsServer*>(server); 197 } 198 199 static jboolean IsRemoteDebuggingEnabled(JNIEnv* env, 200 jobject obj, 201 jint server) { 202 return reinterpret_cast<DevToolsServer*>(server)->IsStarted(); 203 } 204 205 static void SetRemoteDebuggingEnabled(JNIEnv* env, 206 jobject obj, 207 jint server, 208 jboolean enabled) { 209 DevToolsServer* devtools_server = reinterpret_cast<DevToolsServer*>(server); 210 if (enabled) { 211 devtools_server->Start(); 212 } else { 213 devtools_server->Stop(); 214 } 215 } 216