aw_contents_io_thread_client.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  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. #include "android_webview/browser/aw_contents_io_thread_client.h"
  5. #include <map>
  6. #include <memory>
  7. #include <utility>
  8. #include "android_webview/browser/aw_settings.h"
  9. #include "android_webview/browser/network_service/aw_web_resource_intercept_response.h"
  10. #include "android_webview/browser/network_service/aw_web_resource_request.h"
  11. #include "android_webview/browser_jni_headers/AwContentsBackgroundThreadClient_jni.h"
  12. #include "android_webview/browser_jni_headers/AwContentsIoThreadClient_jni.h"
  13. #include "android_webview/common/devtools_instrumentation.h"
  14. #include "base/android/jni_array.h"
  15. #include "base/android/jni_string.h"
  16. #include "base/android/jni_weak_ref.h"
  17. #include "base/bind.h"
  18. #include "base/containers/flat_set.h"
  19. #include "base/lazy_instance.h"
  20. #include "base/logging.h"
  21. #include "base/metrics/histogram_functions.h"
  22. #include "base/metrics/histogram_macros.h"
  23. #include "base/synchronization/lock.h"
  24. #include "base/threading/scoped_blocking_call.h"
  25. #include "components/embedder_support/android/util/input_stream.h"
  26. #include "components/embedder_support/android/util/web_resource_response.h"
  27. #include "content/public/browser/browser_thread.h"
  28. #include "content/public/browser/render_frame_host.h"
  29. #include "content/public/browser/render_process_host.h"
  30. #include "content/public/browser/render_view_host.h"
  31. #include "content/public/browser/web_contents.h"
  32. #include "content/public/browser/web_contents_observer.h"
  33. #include "net/base/data_url.h"
  34. #include "services/network/public/cpp/resource_request.h"
  35. #include "third_party/abseil-cpp/absl/types/optional.h"
  36. using base::LazyInstance;
  37. using base::android::AttachCurrentThread;
  38. using base::android::ConvertUTF8ToJavaString;
  39. using base::android::JavaRef;
  40. using base::android::ScopedJavaLocalRef;
  41. using base::android::ToJavaArrayOfStrings;
  42. using content::BrowserThread;
  43. using content::RenderFrameHost;
  44. using content::WebContents;
  45. using std::map;
  46. using std::pair;
  47. using std::string;
  48. namespace android_webview {
  49. namespace {
  50. typedef map<content::GlobalRenderFrameHostId, JavaObjectWeakGlobalRef>
  51. RenderFrameHostToWeakGlobalRefType;
  52. typedef pair<base::flat_set<RenderFrameHost*>, JavaObjectWeakGlobalRef>
  53. HostsAndWeakGlobalRefPair;
  54. // When browser side navigation is enabled, RenderFrameIDs do not have
  55. // valid render process host and render frame ids for frame navigations.
  56. // We need to identify these by using FrameTreeNodeIds. Furthermore, we need
  57. // to keep track of which RenderFrameHosts are associated with each
  58. // FrameTreeNodeId, so we know when the last RenderFrameHost is deleted (and
  59. // therefore the FrameTreeNodeId should be removed).
  60. typedef map<int, HostsAndWeakGlobalRefPair> FrameTreeNodeToWeakGlobalRefType;
  61. // RfhToIoThreadClientMap -----------------------------------------------------
  62. class RfhToIoThreadClientMap {
  63. public:
  64. static RfhToIoThreadClientMap* GetInstance();
  65. void Set(content::GlobalRenderFrameHostId rfh_id,
  66. const JavaObjectWeakGlobalRef& client);
  67. absl::optional<JavaObjectWeakGlobalRef> Get(
  68. content::GlobalRenderFrameHostId rfh_id);
  69. absl::optional<JavaObjectWeakGlobalRef> Get(int frame_tree_node_id);
  70. // Prefer to call these when RenderFrameHost* is available, because they
  71. // update both maps at the same time.
  72. void Set(RenderFrameHost* rfh, const JavaObjectWeakGlobalRef& client);
  73. void Erase(RenderFrameHost* rfh);
  74. private:
  75. base::Lock map_lock_;
  76. // We maintain two maps simultaneously so that we can always get the correct
  77. // JavaObjectWeakGlobalRef, even when only HostIdPair or FrameTreeNodeId is
  78. // available.
  79. RenderFrameHostToWeakGlobalRefType rfh_to_weak_global_ref_;
  80. FrameTreeNodeToWeakGlobalRefType frame_tree_node_to_weak_global_ref_;
  81. };
  82. // static
  83. LazyInstance<RfhToIoThreadClientMap>::DestructorAtExit g_instance_ =
  84. LAZY_INSTANCE_INITIALIZER;
  85. // static
  86. LazyInstance<JavaObjectWeakGlobalRef>::DestructorAtExit g_sw_instance_ =
  87. LAZY_INSTANCE_INITIALIZER;
  88. // static
  89. RfhToIoThreadClientMap* RfhToIoThreadClientMap::GetInstance() {
  90. return g_instance_.Pointer();
  91. }
  92. void RfhToIoThreadClientMap::Set(content::GlobalRenderFrameHostId rfh_id,
  93. const JavaObjectWeakGlobalRef& client) {
  94. base::AutoLock lock(map_lock_);
  95. rfh_to_weak_global_ref_[rfh_id] = client;
  96. }
  97. absl::optional<JavaObjectWeakGlobalRef> RfhToIoThreadClientMap::Get(
  98. content::GlobalRenderFrameHostId rfh_id) {
  99. base::AutoLock lock(map_lock_);
  100. RenderFrameHostToWeakGlobalRefType::iterator iterator =
  101. rfh_to_weak_global_ref_.find(rfh_id);
  102. if (iterator == rfh_to_weak_global_ref_.end()) {
  103. return absl::nullopt;
  104. } else {
  105. return iterator->second;
  106. }
  107. }
  108. absl::optional<JavaObjectWeakGlobalRef> RfhToIoThreadClientMap::Get(
  109. int frame_tree_node_id) {
  110. base::AutoLock lock(map_lock_);
  111. FrameTreeNodeToWeakGlobalRefType::iterator iterator =
  112. frame_tree_node_to_weak_global_ref_.find(frame_tree_node_id);
  113. if (iterator == frame_tree_node_to_weak_global_ref_.end()) {
  114. return absl::nullopt;
  115. } else {
  116. return iterator->second.second;
  117. }
  118. }
  119. void RfhToIoThreadClientMap::Set(RenderFrameHost* rfh,
  120. const JavaObjectWeakGlobalRef& client) {
  121. int frame_tree_node_id = rfh->GetFrameTreeNodeId();
  122. content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId();
  123. base::AutoLock lock(map_lock_);
  124. // If this FrameTreeNodeId already has an associated JavaObjectWeakGlobalRef,
  125. // add this RenderFrameHost to the hosts set (it's harmless to overwrite the
  126. // JavaObjectWeakGlobalRef). Otherwise, operator[] creates a new map entry and
  127. // we add this RenderFrameHost to the hosts set and insert |client| in the
  128. // pair.
  129. HostsAndWeakGlobalRefPair& current_entry =
  130. frame_tree_node_to_weak_global_ref_[frame_tree_node_id];
  131. current_entry.second = client;
  132. current_entry.first.insert(rfh);
  133. // Always add the entry to the HostIdPair map, since entries are 1:1 with
  134. // RenderFrameHosts.
  135. rfh_to_weak_global_ref_[rfh_id] = client;
  136. }
  137. void RfhToIoThreadClientMap::Erase(RenderFrameHost* rfh) {
  138. int frame_tree_node_id = rfh->GetFrameTreeNodeId();
  139. content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId();
  140. base::AutoLock lock(map_lock_);
  141. HostsAndWeakGlobalRefPair& current_entry =
  142. frame_tree_node_to_weak_global_ref_[frame_tree_node_id];
  143. size_t num_erased = current_entry.first.erase(rfh);
  144. DCHECK(num_erased == 1);
  145. // Only remove this entry from the FrameTreeNodeId map if there are no more
  146. // live RenderFrameHosts.
  147. if (current_entry.first.empty()) {
  148. frame_tree_node_to_weak_global_ref_.erase(frame_tree_node_id);
  149. }
  150. // Always safe to remove the entry from the HostIdPair map, since entries are
  151. // 1:1 with RenderFrameHosts.
  152. rfh_to_weak_global_ref_.erase(rfh_id);
  153. }
  154. // ClientMapEntryUpdater ------------------------------------------------------
  155. class ClientMapEntryUpdater : public content::WebContentsObserver {
  156. public:
  157. ClientMapEntryUpdater(JNIEnv* env,
  158. WebContents* web_contents,
  159. jobject jdelegate);
  160. void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
  161. void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
  162. void WebContentsDestroyed() override;
  163. private:
  164. JavaObjectWeakGlobalRef jdelegate_;
  165. };
  166. ClientMapEntryUpdater::ClientMapEntryUpdater(JNIEnv* env,
  167. WebContents* web_contents,
  168. jobject jdelegate)
  169. : content::WebContentsObserver(web_contents), jdelegate_(env, jdelegate) {
  170. DCHECK(web_contents);
  171. DCHECK(jdelegate);
  172. if (web_contents->GetPrimaryMainFrame())
  173. RenderFrameCreated(web_contents->GetPrimaryMainFrame());
  174. }
  175. void ClientMapEntryUpdater::RenderFrameCreated(RenderFrameHost* rfh) {
  176. RfhToIoThreadClientMap::GetInstance()->Set(rfh, jdelegate_);
  177. }
  178. void ClientMapEntryUpdater::RenderFrameDeleted(RenderFrameHost* rfh) {
  179. RfhToIoThreadClientMap::GetInstance()->Erase(rfh);
  180. }
  181. void ClientMapEntryUpdater::WebContentsDestroyed() {
  182. delete this;
  183. }
  184. } // namespace
  185. // AwContentsIoThreadClient -----------------------------------------------
  186. // static
  187. // Wrap an optional |JavaObjectWeakGlobalRef| to a Java
  188. // |AwContentsIoThreadClient| in a native |AwContentsIoThreadClient| by getting
  189. // a scoped local reference. This will return |nullptr| if either the optional
  190. // is empty or the weak reference has already expired.
  191. std::unique_ptr<AwContentsIoThreadClient> WrapOptionalWeakRef(
  192. absl::optional<JavaObjectWeakGlobalRef> opt_delegate_weak_ref) {
  193. if (opt_delegate_weak_ref) {
  194. JNIEnv* env = AttachCurrentThread();
  195. ScopedJavaLocalRef<jobject> java_delegate = opt_delegate_weak_ref->get(env);
  196. if (java_delegate) {
  197. return std::make_unique<AwContentsIoThreadClient>(java_delegate);
  198. }
  199. }
  200. return nullptr;
  201. }
  202. // static
  203. std::unique_ptr<AwContentsIoThreadClient> AwContentsIoThreadClient::FromID(
  204. content::GlobalRenderFrameHostId render_frame_host_id) {
  205. return WrapOptionalWeakRef(
  206. RfhToIoThreadClientMap::GetInstance()->Get(render_frame_host_id));
  207. }
  208. std::unique_ptr<AwContentsIoThreadClient> AwContentsIoThreadClient::FromID(
  209. int frame_tree_node_id) {
  210. return WrapOptionalWeakRef(
  211. RfhToIoThreadClientMap::GetInstance()->Get(frame_tree_node_id));
  212. }
  213. // static
  214. void AwContentsIoThreadClient::SubFrameCreated(int render_process_id,
  215. int parent_render_frame_id,
  216. int child_render_frame_id) {
  217. content::GlobalRenderFrameHostId parent_rfh_id(render_process_id,
  218. parent_render_frame_id);
  219. content::GlobalRenderFrameHostId child_rfh_id(render_process_id,
  220. child_render_frame_id);
  221. RfhToIoThreadClientMap* map = RfhToIoThreadClientMap::GetInstance();
  222. absl::optional<JavaObjectWeakGlobalRef> opt_delegate_weak_ref =
  223. map->Get(parent_rfh_id);
  224. if (opt_delegate_weak_ref) {
  225. map->Set(child_rfh_id, opt_delegate_weak_ref.value());
  226. } else {
  227. // It is possible to not find a mapping for the parent rfh_id if the WebView
  228. // is in the process of being destroyed, and the mapping has already been
  229. // erased.
  230. LOG(WARNING) << "No IoThreadClient associated with parent RenderFrameHost.";
  231. }
  232. }
  233. // static
  234. void AwContentsIoThreadClient::Associate(WebContents* web_contents,
  235. const JavaRef<jobject>& jclient) {
  236. JNIEnv* env = AttachCurrentThread();
  237. // The ClientMapEntryUpdater lifespan is tied to the WebContents.
  238. new ClientMapEntryUpdater(env, web_contents, jclient.obj());
  239. }
  240. // static
  241. void AwContentsIoThreadClient::SetServiceWorkerIoThreadClient(
  242. const base::android::JavaRef<jobject>& jclient,
  243. const base::android::JavaRef<jobject>& browser_context) {
  244. // TODO: currently there is only one browser context so it is ok to
  245. // store in a global variable, in the future use browser_context to
  246. // obtain the correct instance.
  247. JavaObjectWeakGlobalRef temp(AttachCurrentThread(), jclient.obj());
  248. g_sw_instance_.Get() = temp;
  249. }
  250. // static
  251. std::unique_ptr<AwContentsIoThreadClient>
  252. AwContentsIoThreadClient::GetServiceWorkerIoThreadClient() {
  253. return WrapOptionalWeakRef(absl::make_optional(g_sw_instance_.Get()));
  254. }
  255. AwContentsIoThreadClient::AwContentsIoThreadClient(const JavaRef<jobject>& obj)
  256. : java_object_(obj) {
  257. DCHECK(java_object_);
  258. }
  259. AwContentsIoThreadClient::~AwContentsIoThreadClient() = default;
  260. AwContentsIoThreadClient::CacheMode AwContentsIoThreadClient::GetCacheMode()
  261. const {
  262. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  263. JNIEnv* env = AttachCurrentThread();
  264. return static_cast<AwContentsIoThreadClient::CacheMode>(
  265. Java_AwContentsIoThreadClient_getCacheMode(env, java_object_));
  266. }
  267. namespace {
  268. // Used to specify what kind of url was intercepted by the embedded
  269. // using shouldIntercepterRequest callback.
  270. // Note: these values are persisted in UMA logs, so they should never be
  271. // renumbered or reused.
  272. // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.android_webview
  273. enum class InterceptionType {
  274. kNoIntercept,
  275. kOther,
  276. kHTTP,
  277. kHTTPS,
  278. kFILE,
  279. kDATA,
  280. // Magic constant used by the histogram macros.
  281. kMaxValue = kDATA,
  282. };
  283. // Record UMA whether the request was intercepted and if so what kind of scheme.
  284. void RecordInterceptedScheme(bool response_is_null, const std::string& url) {
  285. InterceptionType type = InterceptionType::kNoIntercept;
  286. if (!response_is_null) {
  287. GURL gurl(url);
  288. if (gurl.SchemeIs(url::kHttpScheme)) {
  289. type = InterceptionType::kHTTP;
  290. } else if (gurl.SchemeIs(url::kHttpsScheme)) {
  291. type = InterceptionType::kHTTPS;
  292. } else if (gurl.SchemeIs(url::kFileScheme)) {
  293. type = InterceptionType::kFILE;
  294. } else if (gurl.SchemeIs(url::kDataScheme)) {
  295. type = InterceptionType::kDATA;
  296. } else {
  297. type = InterceptionType::kOther;
  298. }
  299. }
  300. UMA_HISTOGRAM_ENUMERATION(
  301. "Android.WebView.ShouldInterceptRequest.InterceptionType2", type);
  302. }
  303. std::unique_ptr<AwWebResourceInterceptResponse> NoInterceptRequest() {
  304. return nullptr;
  305. }
  306. std::unique_ptr<AwWebResourceInterceptResponse> RunShouldInterceptRequest(
  307. AwWebResourceRequest request,
  308. JavaObjectWeakGlobalRef ref) {
  309. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  310. base::BlockingType::MAY_BLOCK);
  311. JNIEnv* env = AttachCurrentThread();
  312. base::android::ScopedJavaLocalRef<jobject> obj = ref.get(env);
  313. if (!obj) {
  314. return NoInterceptRequest();
  315. }
  316. AwWebResourceRequest::AwJavaWebResourceRequest java_web_resource_request;
  317. AwWebResourceRequest::ConvertToJava(env, request, &java_web_resource_request);
  318. devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback(
  319. "shouldInterceptRequest");
  320. ScopedJavaLocalRef<jobject> java_ref =
  321. Java_AwContentsBackgroundThreadClient_shouldInterceptRequestFromNative(
  322. env, obj, java_web_resource_request.jurl,
  323. request.is_outermost_main_frame, request.has_user_gesture,
  324. java_web_resource_request.jmethod,
  325. java_web_resource_request.jheader_names,
  326. java_web_resource_request.jheader_values);
  327. DCHECK(java_ref)
  328. << "shouldInterceptRequestFromNative() should return non-null value";
  329. auto web_resource_intercept_response =
  330. std::make_unique<AwWebResourceInterceptResponse>(java_ref);
  331. bool has_response = web_resource_intercept_response->HasResponse(env);
  332. RecordInterceptedScheme(!has_response, request.url);
  333. return web_resource_intercept_response;
  334. }
  335. } // namespace
  336. void AwContentsIoThreadClient::ShouldInterceptRequestAsync(
  337. AwWebResourceRequest request,
  338. ShouldInterceptRequestResponseCallback callback) {
  339. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  340. base::OnceCallback<std::unique_ptr<AwWebResourceInterceptResponse>()>
  341. get_response = base::BindOnce(&NoInterceptRequest);
  342. JNIEnv* env = AttachCurrentThread();
  343. if (!bg_thread_client_object_) {
  344. bg_thread_client_object_.Reset(
  345. Java_AwContentsIoThreadClient_getBackgroundThreadClient(env,
  346. java_object_));
  347. }
  348. if (bg_thread_client_object_) {
  349. get_response = base::BindOnce(
  350. &RunShouldInterceptRequest, std::move(request),
  351. JavaObjectWeakGlobalRef(env, bg_thread_client_object_.obj()));
  352. }
  353. base::PostTaskAndReplyWithResult(sequenced_task_runner_.get(), FROM_HERE,
  354. std::move(get_response),
  355. std::move(callback));
  356. }
  357. bool AwContentsIoThreadClient::ShouldBlockContentUrls() const {
  358. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  359. JNIEnv* env = AttachCurrentThread();
  360. return Java_AwContentsIoThreadClient_shouldBlockContentUrls(env,
  361. java_object_);
  362. }
  363. bool AwContentsIoThreadClient::ShouldBlockFileUrls() const {
  364. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  365. JNIEnv* env = AttachCurrentThread();
  366. return Java_AwContentsIoThreadClient_shouldBlockFileUrls(env, java_object_);
  367. }
  368. bool AwContentsIoThreadClient::ShouldAcceptThirdPartyCookies() const {
  369. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  370. JNIEnv* env = AttachCurrentThread();
  371. return Java_AwContentsIoThreadClient_shouldAcceptThirdPartyCookies(
  372. env, java_object_);
  373. }
  374. bool AwContentsIoThreadClient::GetSafeBrowsingEnabled() const {
  375. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  376. JNIEnv* env = AttachCurrentThread();
  377. return Java_AwContentsIoThreadClient_getSafeBrowsingEnabled(env,
  378. java_object_);
  379. }
  380. bool AwContentsIoThreadClient::ShouldBlockNetworkLoads() const {
  381. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  382. JNIEnv* env = AttachCurrentThread();
  383. return Java_AwContentsIoThreadClient_shouldBlockNetworkLoads(env,
  384. java_object_);
  385. }
  386. AwSettings::RequestedWithHeaderMode
  387. AwContentsIoThreadClient::GetRequestedWithHeaderMode() const {
  388. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  389. JNIEnv* env = AttachCurrentThread();
  390. return static_cast<AwSettings::RequestedWithHeaderMode>(
  391. Java_AwContentsIoThreadClient_getRequestedWithHeaderMode(env,
  392. java_object_));
  393. }
  394. } // namespace android_webview