dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 1 | // Copyright 2015 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 | |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 5 | #include "chrome/browser/android/devtools_manager_delegate_android.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 6 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 7 | #include <map> |
Peter Boström | 08e7ed8 | 2021-04-19 17:49:59 | [diff] [blame] | 8 | #include <memory> |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 9 | |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 10 | #include "base/bind.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 11 | #include "base/strings/string_number_conversions.h" |
| 12 | #include "base/strings/utf_string_conversions.h" |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 13 | #include "build/build_config.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 14 | #include "chrome/browser/android/tab_android.h" |
Richard Knoll | 7b9de30 | 2021-04-06 23:05:42 | [diff] [blame] | 15 | #include "chrome/browser/profiles/profile_manager.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 16 | #include "chrome/browser/ui/android/tab_model/tab_model.h" |
| 17 | #include "chrome/browser/ui/android/tab_model/tab_model_list.h" |
pfeldman | 1062876 | 2016-09-08 07:59:26 | [diff] [blame] | 18 | #include "chrome/grit/browser_resources.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 19 | #include "content/public/browser/devtools_agent_host.h" |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 20 | #include "content/public/browser/devtools_agent_host_client.h" |
| 21 | #include "content/public/browser/devtools_external_agent_proxy.h" |
| 22 | #include "content/public/browser/devtools_external_agent_proxy_delegate.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 23 | #include "content/public/browser/web_contents.h" |
pfeldman | 1062876 | 2016-09-08 07:59:26 | [diff] [blame] | 24 | #include "ui/base/resource/resource_bundle.h" |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 25 | |
| 26 | using content::DevToolsAgentHost; |
| 27 | using content::WebContents; |
| 28 | |
| 29 | namespace { |
| 30 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 31 | class ClientProxy : public content::DevToolsAgentHostClient { |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 32 | public: |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 33 | explicit ClientProxy(content::DevToolsExternalAgentProxy* proxy) |
| 34 | : proxy_(proxy) {} |
Peter Boström | 53c6c595 | 2021-09-17 09:41:26 | [diff] [blame^] | 35 | |
| 36 | ClientProxy(const ClientProxy&) = delete; |
| 37 | ClientProxy& operator=(const ClientProxy&) = delete; |
| 38 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 39 | ~ClientProxy() override {} |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 40 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 41 | void DispatchProtocolMessage(DevToolsAgentHost* agent_host, |
Johannes Henkel | 21e19401 | 2019-12-20 03:23:17 | [diff] [blame] | 42 | base::span<const uint8_t> message) override { |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 43 | proxy_->DispatchOnClientHost(message); |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 44 | } |
| 45 | |
Pavel Feldman | a344d93 | 2017-10-31 20:24:52 | [diff] [blame] | 46 | void AgentHostClosed(DevToolsAgentHost* agent_host) override { |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 47 | proxy_->ConnectionClosed(); |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 48 | } |
| 49 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 50 | private: |
| 51 | content::DevToolsExternalAgentProxy* proxy_; |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 52 | }; |
| 53 | |
| 54 | class TabProxyDelegate : public content::DevToolsExternalAgentProxyDelegate { |
| 55 | public: |
| 56 | explicit TabProxyDelegate(TabAndroid* tab) |
| 57 | : tab_id_(tab->GetAndroidId()), |
| 58 | title_(base::UTF16ToUTF8(tab->GetTitle())), |
| 59 | url_(tab->GetURL()), |
| 60 | agent_host_(tab->web_contents() |
| 61 | ? DevToolsAgentHost::GetOrCreateFor(tab->web_contents()) |
| 62 | : nullptr) {} |
| 63 | |
Peter Boström | 53c6c595 | 2021-09-17 09:41:26 | [diff] [blame^] | 64 | TabProxyDelegate(const TabProxyDelegate&) = delete; |
| 65 | TabProxyDelegate& operator=(const TabProxyDelegate&) = delete; |
| 66 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 67 | ~TabProxyDelegate() override {} |
| 68 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 69 | void Attach(content::DevToolsExternalAgentProxy* proxy) override { |
Peter Boström | 08e7ed8 | 2021-04-19 17:49:59 | [diff] [blame] | 70 | proxies_[proxy] = std::make_unique<ClientProxy>(proxy); |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 71 | MaterializeAgentHost(); |
pfeldman | 2236ce0a | 2016-09-20 23:59:46 | [diff] [blame] | 72 | if (agent_host_) |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 73 | agent_host_->AttachClient(proxies_[proxy].get()); |
mohsen | d8fe6fb4 | 2016-08-25 01:55:10 | [diff] [blame] | 74 | } |
| 75 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 76 | void Detach(content::DevToolsExternalAgentProxy* proxy) override { |
| 77 | auto it = proxies_.find(proxy); |
| 78 | if (it == proxies_.end()) |
| 79 | return; |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 80 | if (agent_host_) |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 81 | agent_host_->DetachClient(it->second.get()); |
| 82 | proxies_.erase(it); |
| 83 | if (proxies_.empty()) |
| 84 | agent_host_ = nullptr; |
mohsen | d8fe6fb4 | 2016-08-25 01:55:10 | [diff] [blame] | 85 | } |
| 86 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 87 | std::string GetType() override { |
| 88 | return agent_host_ ? agent_host_->GetType() : DevToolsAgentHost::kTypePage; |
mohsen | d8fe6fb4 | 2016-08-25 01:55:10 | [diff] [blame] | 89 | } |
| 90 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 91 | std::string GetTitle() override { |
| 92 | return agent_host_ ? agent_host_->GetTitle() : title_; |
mohsen | d8fe6fb4 | 2016-08-25 01:55:10 | [diff] [blame] | 93 | } |
| 94 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 95 | std::string GetDescription() override { |
| 96 | return agent_host_ ? agent_host_->GetDescription() : ""; |
mohsen | d8fe6fb4 | 2016-08-25 01:55:10 | [diff] [blame] | 97 | } |
| 98 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 99 | GURL GetURL() override { |
| 100 | return agent_host_ ? agent_host_->GetURL() : url_; |
| 101 | } |
| 102 | |
| 103 | GURL GetFaviconURL() override { |
| 104 | return agent_host_ ? agent_host_->GetFaviconURL() : GURL(); |
| 105 | } |
| 106 | |
pfeldman | e7d2e41 | 2016-09-23 16:41:51 | [diff] [blame] | 107 | std::string GetFrontendURL() override { |
| 108 | return std::string(); |
| 109 | } |
| 110 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 111 | bool Activate() override { |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 112 | TabModel* model; |
| 113 | int index; |
| 114 | if (!FindTab(&model, &index)) |
| 115 | return false; |
| 116 | model->SetActiveIndex(index); |
| 117 | return true; |
| 118 | } |
| 119 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 120 | void Reload() override { |
| 121 | MaterializeAgentHost(); |
| 122 | if (agent_host_) |
| 123 | agent_host_->Reload(); |
| 124 | } |
| 125 | |
| 126 | bool Close() override { |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 127 | TabModel* model; |
| 128 | int index; |
| 129 | if (!FindTab(&model, &index)) |
| 130 | return false; |
| 131 | model->CloseTabAt(index); |
| 132 | return true; |
| 133 | } |
| 134 | |
pfeldman | 97088372 | 2017-02-08 06:08:53 | [diff] [blame] | 135 | base::TimeTicks GetLastActivityTime() override { |
| 136 | return agent_host_ ? agent_host_->GetLastActivityTime() : base::TimeTicks(); |
| 137 | } |
| 138 | |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 139 | void SendMessageToBackend(content::DevToolsExternalAgentProxy* proxy, |
Johannes Henkel | 21e19401 | 2019-12-20 03:23:17 | [diff] [blame] | 140 | base::span<const uint8_t> message) override { |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 141 | auto it = proxies_.find(proxy); |
| 142 | if (it == proxies_.end()) |
| 143 | return; |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 144 | if (agent_host_) |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 145 | agent_host_->DispatchProtocolMessage(it->second.get(), message); |
gab | 0dccfef | 2015-05-20 18:43:39 | [diff] [blame] | 146 | } |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 147 | |
pfeldman | a9e7dda | 2016-08-26 14:35:17 | [diff] [blame] | 148 | private: |
| 149 | void MaterializeAgentHost() { |
| 150 | if (agent_host_) |
| 151 | return; |
| 152 | TabModel* model; |
| 153 | int index; |
| 154 | if (!FindTab(&model, &index)) |
| 155 | return; |
| 156 | WebContents* web_contents = model->GetWebContentsAt(index); |
| 157 | if (!web_contents) |
| 158 | return; |
| 159 | agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents); |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | bool FindTab(TabModel** model_result, int* index_result) const { |
Tomasz Wiszkowski | 066ab984 | 2021-03-23 00:37:31 | [diff] [blame] | 163 | for (TabModel* model : TabModelList::models()) { |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 164 | for (int i = 0; i < model->GetTabCount(); ++i) { |
| 165 | TabAndroid* tab = model->GetTabAt(i); |
| 166 | if (tab && tab->GetAndroidId() == tab_id_) { |
| 167 | *model_result = model; |
| 168 | *index_result = i; |
| 169 | return true; |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | return false; |
| 174 | } |
| 175 | |
| 176 | const int tab_id_; |
| 177 | const std::string title_; |
| 178 | const GURL url_; |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 179 | scoped_refptr<DevToolsAgentHost> agent_host_; |
Dmitry Gozman | f7a1c2f | 2017-09-12 19:37:02 | [diff] [blame] | 180 | std::map<content::DevToolsExternalAgentProxy*, std::unique_ptr<ClientProxy>> |
| 181 | proxies_; |
dgozman | ec2b982a | 2015-04-28 10:36:39 | [diff] [blame] | 182 | }; |
| 183 | |
pfeldman | 82f2940 | 2017-04-24 20:58:02 | [diff] [blame] | 184 | scoped_refptr<DevToolsAgentHost> DevToolsAgentHostForTab(TabAndroid* tab) { |
| 185 | scoped_refptr<DevToolsAgentHost> result = tab->GetDevToolsAgentHost(); |
| 186 | if (result) |
| 187 | return result; |
| 188 | |
Raul Tambre | fff51b75 | 2019-02-04 13:09:47 | [diff] [blame] | 189 | result = DevToolsAgentHost::Forward(base::NumberToString(tab->GetAndroidId()), |
Jinho Bang | 7fa90e87 | 2018-01-15 18:04:12 | [diff] [blame] | 190 | std::make_unique<TabProxyDelegate>(tab)); |
pfeldman | 82f2940 | 2017-04-24 20:58:02 | [diff] [blame] | 191 | tab->SetDevToolsAgentHost(result); |
| 192 | return result; |
| 193 | } |
| 194 | |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 195 | } // namespace |
| 196 | |
Andrey Kosyakov | 24f3316 | 2017-09-14 22:41:40 | [diff] [blame] | 197 | DevToolsManagerDelegateAndroid::DevToolsManagerDelegateAndroid() = default; |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 198 | |
Andrey Kosyakov | 24f3316 | 2017-09-14 22:41:40 | [diff] [blame] | 199 | DevToolsManagerDelegateAndroid::~DevToolsManagerDelegateAndroid() = default; |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 200 | |
Richard Knoll | 7b9de30 | 2021-04-06 23:05:42 | [diff] [blame] | 201 | content::BrowserContext* |
| 202 | DevToolsManagerDelegateAndroid::GetDefaultBrowserContext() { |
| 203 | return ProfileManager::GetActiveUserProfile()->GetOriginalProfile(); |
| 204 | } |
| 205 | |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 206 | std::string DevToolsManagerDelegateAndroid::GetTargetType( |
dgozman | 3234f37 | 2017-06-09 03:03:55 | [diff] [blame] | 207 | content::WebContents* web_contents) { |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 208 | TabAndroid* tab = web_contents ? TabAndroid::FromWebContents(web_contents) |
| 209 | : nullptr; |
| 210 | return tab ? DevToolsAgentHost::kTypePage : |
| 211 | DevToolsAgentHost::kTypeOther; |
| 212 | } |
| 213 | |
pfeldman | 82f2940 | 2017-04-24 20:58:02 | [diff] [blame] | 214 | DevToolsAgentHost::List |
| 215 | DevToolsManagerDelegateAndroid::RemoteDebuggingTargets() { |
pfeldman | e28eab4 | 2016-09-21 23:00:53 | [diff] [blame] | 216 | // Enumerate existing tabs, including the ones with no WebContents. |
| 217 | DevToolsAgentHost::List result; |
| 218 | std::set<WebContents*> tab_web_contents; |
Tomasz Wiszkowski | 066ab984 | 2021-03-23 00:37:31 | [diff] [blame] | 219 | for (const TabModel* model : TabModelList::models()) { |
pfeldman | e28eab4 | 2016-09-21 23:00:53 | [diff] [blame] | 220 | for (int i = 0; i < model->GetTabCount(); ++i) { |
| 221 | TabAndroid* tab = model->GetTabAt(i); |
| 222 | if (!tab) |
| 223 | continue; |
| 224 | |
| 225 | if (tab->web_contents()) |
| 226 | tab_web_contents.insert(tab->web_contents()); |
pfeldman | 82f2940 | 2017-04-24 20:58:02 | [diff] [blame] | 227 | result.push_back(DevToolsAgentHostForTab(tab)); |
pfeldman | e28eab4 | 2016-09-21 23:00:53 | [diff] [blame] | 228 | } |
| 229 | } |
| 230 | |
| 231 | // Add descriptors for targets not associated with any tabs. |
| 232 | DevToolsAgentHost::List agents = DevToolsAgentHost::GetOrCreateAll(); |
| 233 | for (DevToolsAgentHost::List::iterator it = agents.begin(); |
| 234 | it != agents.end(); ++it) { |
| 235 | if (WebContents* web_contents = (*it)->GetWebContents()) { |
| 236 | if (tab_web_contents.find(web_contents) != tab_web_contents.end()) |
| 237 | continue; |
| 238 | } |
| 239 | result.push_back(*it); |
| 240 | } |
| 241 | |
pfeldman | 82f2940 | 2017-04-24 20:58:02 | [diff] [blame] | 242 | return result; |
pfeldman | e28eab4 | 2016-09-21 23:00:53 | [diff] [blame] | 243 | } |
| 244 | |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 245 | scoped_refptr<DevToolsAgentHost> |
| 246 | DevToolsManagerDelegateAndroid::CreateNewTarget(const GURL& url) { |
Tomasz Wiszkowski | 066ab984 | 2021-03-23 00:37:31 | [diff] [blame] | 247 | if (TabModelList::models().empty()) |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 248 | return nullptr; |
| 249 | |
Tomasz Wiszkowski | 066ab984 | 2021-03-23 00:37:31 | [diff] [blame] | 250 | TabModel* tab_model = TabModelList::models()[0]; |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 251 | if (!tab_model) |
| 252 | return nullptr; |
| 253 | |
| 254 | WebContents* web_contents = tab_model->CreateNewTabForDevTools(url); |
| 255 | if (!web_contents) |
| 256 | return nullptr; |
| 257 | |
| 258 | TabAndroid* tab = TabAndroid::FromWebContents(web_contents); |
pfeldman | 82f2940 | 2017-04-24 20:58:02 | [diff] [blame] | 259 | return tab ? DevToolsAgentHostForTab(tab) : nullptr; |
pfeldman | 1062876 | 2016-09-08 07:59:26 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | std::string DevToolsManagerDelegateAndroid::GetDiscoveryPageHTML() { |
Sam Maier | e0f6e047 | 2019-10-31 21:37:49 | [diff] [blame] | 263 | return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( |
Andrew Grieve | 088fef7 | 2019-10-08 15:57:33 | [diff] [blame] | 264 | IDR_DEVTOOLS_DISCOVERY_PAGE_HTML); |
Pavel Feldman | 43f56b7c | 2016-08-30 00:04:35 | [diff] [blame] | 265 | } |
| 266 | |
Pavel Feldman | 77da4d5 | 2017-08-05 11:59:24 | [diff] [blame] | 267 | bool DevToolsManagerDelegateAndroid::IsBrowserTargetDiscoverable() { |
| 268 | return true; |
| 269 | } |