blob: f4ef7689d250cc0a880e722122c2e9e545257421 [file] [log] [blame]
Scott Violet009c09c2020-01-18 00:57:181// Copyright 2020 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 "weblayer/browser/browser_impl.h"
6
7#include <algorithm>
8
Mugdha Lakhani5f8de7cc2020-03-10 20:43:369#include "base/callback_forward.h"
Scott Violetbb6c84552020-01-29 23:35:2410#include "base/containers/unique_ptr_adapters.h"
Gabriel Charette9f60dd12020-03-06 20:48:0411#include "base/memory/ptr_util.h"
Scott Violet87450ce2020-01-23 01:56:2512#include "base/path_service.h"
13#include "components/base32/base32.h"
14#include "content/public/browser/browser_context.h"
Bo Liuabea5dcc2020-04-20 16:06:2315#include "content/public/common/web_preferences.h"
Scott Violet1e3e0b42020-04-02 14:43:2216#include "weblayer/browser/feature_list_creator.h"
Scott Violet9843d0a2020-02-11 22:38:0717#include "weblayer/browser/persistence/browser_persister.h"
Scott Violet343f4ec2020-01-30 02:58:0818#include "weblayer/browser/persistence/minimal_browser_persister.h"
Scott Violet009c09c2020-01-18 00:57:1819#include "weblayer/browser/profile_impl.h"
20#include "weblayer/browser/tab_impl.h"
Scott Violet87450ce2020-01-23 01:56:2521#include "weblayer/common/weblayer_paths.h"
Scott Violet009c09c2020-01-18 00:57:1822#include "weblayer/public/browser_observer.h"
23
24#if defined(OS_ANDROID)
25#include "base/android/callback_android.h"
Scott Violetbf8b8aa72020-01-28 19:37:3226#include "base/android/jni_array.h"
Scott Violet009c09c2020-01-18 00:57:1827#include "base/android/jni_string.h"
28#include "base/json/json_writer.h"
Tim Volodine9839f182020-04-23 17:51:2529#include "weblayer/browser/browser_process.h"
Scott Violet009c09c2020-01-18 00:57:1830#include "weblayer/browser/java/jni/BrowserImpl_jni.h"
31#endif
32
Scott Violet90564152020-01-31 18:31:3033#if defined(OS_ANDROID)
34using base::android::AttachCurrentThread;
35using base::android::JavaParamRef;
36using base::android::ScopedJavaLocalRef;
37#endif
38
Scott Violet009c09c2020-01-18 00:57:1839namespace weblayer {
40
Tim Volodine9839f182020-04-23 17:51:2541// TODO(timvolodine): consider using an observer for this, crbug.com/1068713.
42int BrowserImpl::browser_count_ = 0;
43
Scott Violetbf8b8aa72020-01-28 19:37:3244std::unique_ptr<Browser> Browser::Create(
45 Profile* profile,
46 const PersistenceInfo* persistence_info) {
Scott Violetb7df9d62020-01-31 16:18:4947 // BrowserImpl's constructor is private.
48 auto browser =
49 base::WrapUnique(new BrowserImpl(static_cast<ProfileImpl*>(profile)));
Scott Violetbf8b8aa72020-01-28 19:37:3250 if (persistence_info)
Scott Violetb7df9d62020-01-31 16:18:4951 browser->RestoreStateIfNecessary(*persistence_info);
52 return browser;
Scott Violet87450ce2020-01-23 01:56:2553}
Scott Violet009c09c2020-01-18 00:57:1854
55BrowserImpl::~BrowserImpl() {
Scott Violetbb6c84552020-01-29 23:35:2456#if defined(OS_ANDROID)
57 // Android side should always remove tabs first (because the Java Tab class
58 // owns the C++ Tab). See BrowserImpl.destroy() (in the Java BrowserImpl
59 // class).
60 DCHECK(tabs_.empty());
61#else
62 while (!tabs_.empty())
63 RemoveTab(tabs_.back().get());
64#endif
Bo Liude377632020-02-10 19:23:4965 profile_->DecrementBrowserImplCount();
Tim Volodine9839f182020-04-23 17:51:2566 browser_count_--;
67 DCHECK(browser_count_ >= 0);
68
69#if defined(OS_ANDROID)
70 if (browser_count_ == 0) {
71 weblayer::BrowserProcess::GetInstance()->StopSafeBrowsingService();
72 }
73#endif
Scott Violet009c09c2020-01-18 00:57:1874}
75
Scott Violet58ad5a32020-01-23 22:07:2776TabImpl* BrowserImpl::CreateTabForSessionRestore(
Scott Violetb2e0cf12020-03-09 18:46:4377 std::unique_ptr<content::WebContents> web_contents,
78 const std::string& guid) {
Scott Violetbb6c84552020-01-29 23:35:2479 std::unique_ptr<TabImpl> tab =
Scott Violetb2e0cf12020-03-09 18:46:4380 std::make_unique<TabImpl>(profile_, std::move(web_contents), guid);
Scott Violet58ad5a32020-01-23 22:07:2781#if defined(OS_ANDROID)
Scott Violet58ad5a32020-01-23 22:07:2782 Java_BrowserImpl_createTabForSessionRestore(
Scott Violet90564152020-01-31 18:31:3083 AttachCurrentThread(), java_impl_, reinterpret_cast<jlong>(tab.get()));
Scott Violet58ad5a32020-01-23 22:07:2784#endif
Scott Violetbb6c84552020-01-29 23:35:2485 TabImpl* tab_ptr = tab.get();
86 AddTab(std::move(tab));
87 return tab_ptr;
Scott Violet58ad5a32020-01-23 22:07:2788}
89
Scott Violet009c09c2020-01-18 00:57:1890#if defined(OS_ANDROID)
Bo Liu7f0b7ee2020-05-01 02:43:0791bool BrowserImpl::CompositorHasSurface() {
92 return Java_BrowserImpl_compositorHasSurface(AttachCurrentThread(),
93 java_impl_);
94}
95
Scott Violet009c09c2020-01-18 00:57:1896void BrowserImpl::AddTab(JNIEnv* env,
Scott Violet009c09c2020-01-18 00:57:1897 long native_tab) {
Scott Violetbb6c84552020-01-29 23:35:2498 TabImpl* tab = reinterpret_cast<TabImpl*>(native_tab);
99 std::unique_ptr<Tab> owned_tab;
100 if (tab->browser())
101 owned_tab = tab->browser()->RemoveTab(tab);
102 else
103 owned_tab.reset(tab);
104 AddTab(std::move(owned_tab));
Scott Violet009c09c2020-01-18 00:57:18105}
106
107void BrowserImpl::RemoveTab(JNIEnv* env,
Scott Violet009c09c2020-01-18 00:57:18108 long native_tab) {
Scott Violetbb6c84552020-01-29 23:35:24109 // The Java side owns the Tab.
110 RemoveTab(reinterpret_cast<TabImpl*>(native_tab)).release();
Scott Violet009c09c2020-01-18 00:57:18111}
112
Scott Violet0ccd63292020-05-03 02:32:45113ScopedJavaLocalRef<jobjectArray> BrowserImpl::GetTabs(JNIEnv* env) {
Scott Violet90564152020-01-31 18:31:30114 ScopedJavaLocalRef<jclass> clazz =
Scott Violet009c09c2020-01-18 00:57:18115 base::android::GetClass(env, "org/chromium/weblayer_private/TabImpl");
116 jobjectArray tabs = env->NewObjectArray(tabs_.size(), clazz.obj(),
117 nullptr /* initialElement */);
118 base::android::CheckException(env);
119
120 for (size_t i = 0; i < tabs_.size(); ++i) {
Scott Violetbb6c84552020-01-29 23:35:24121 TabImpl* tab = static_cast<TabImpl*>(tabs_[i].get());
Scott Violet009c09c2020-01-18 00:57:18122 env->SetObjectArrayElement(tabs, i, tab->GetJavaTab().obj());
123 }
Scott Violet90564152020-01-31 18:31:30124 return ScopedJavaLocalRef<jobjectArray>(env, tabs);
Scott Violet009c09c2020-01-18 00:57:18125}
126
Scott Violet90564152020-01-31 18:31:30127void BrowserImpl::SetActiveTab(JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30128 long native_tab) {
Scott Violet009c09c2020-01-18 00:57:18129 SetActiveTab(reinterpret_cast<TabImpl*>(native_tab));
130}
131
Scott Violet0ccd63292020-05-03 02:32:45132ScopedJavaLocalRef<jobject> BrowserImpl::GetActiveTab(JNIEnv* env) {
Scott Violet009c09c2020-01-18 00:57:18133 if (!active_tab_)
134 return nullptr;
Scott Violet90564152020-01-31 18:31:30135 return ScopedJavaLocalRef<jobject>(active_tab_->GetJavaTab());
Scott Violet009c09c2020-01-18 00:57:18136}
Scott Violet58ad5a32020-01-23 22:07:27137
Scott Violet0ccd63292020-05-03 02:32:45138void BrowserImpl::PrepareForShutdown(JNIEnv* env) {
Scott Violet58ad5a32020-01-23 22:07:27139 PrepareForShutdown();
140}
141
Scott Violet0ccd63292020-05-03 02:32:45142ScopedJavaLocalRef<jstring> BrowserImpl::GetPersistenceId(JNIEnv* env) {
Scott Violet90564152020-01-31 18:31:30143 return ScopedJavaLocalRef<jstring>(
Scott Violetbf8b8aa72020-01-28 19:37:32144 base::android::ConvertUTF8ToJavaString(env, GetPersistenceId()));
145}
146
Scott Violet0ccd63292020-05-03 02:32:45147void BrowserImpl::SaveBrowserPersisterIfNecessary(JNIEnv* env) {
Scott Violet9843d0a2020-02-11 22:38:07148 browser_persister_->SaveIfNecessary();
Scott Violetbf8b8aa72020-01-28 19:37:32149}
150
Scott Violet9843d0a2020-02-11 22:38:07151ScopedJavaLocalRef<jbyteArray> BrowserImpl::GetBrowserPersisterCryptoKey(
Scott Violet0ccd63292020-05-03 02:32:45152 JNIEnv* env) {
Scott Violetbf8b8aa72020-01-28 19:37:32153 std::vector<uint8_t> key;
Scott Violet9843d0a2020-02-11 22:38:07154 if (browser_persister_)
155 key = browser_persister_->GetCryptoKey();
Scott Violetbf8b8aa72020-01-28 19:37:32156 return base::android::ToJavaByteArray(env, key);
Scott Violet58ad5a32020-01-23 22:07:27157}
158
Scott Violet90564152020-01-31 18:31:30159ScopedJavaLocalRef<jbyteArray> BrowserImpl::GetMinimalPersistenceState(
Scott Violet0ccd63292020-05-03 02:32:45160 JNIEnv* env) {
Scott Violet343f4ec2020-01-30 02:58:08161 auto state = GetMinimalPersistenceState();
162 return base::android::ToJavaByteArray(env, &(state.front()), state.size());
163}
164
Scott Violetb7df9d62020-01-31 16:18:49165void BrowserImpl::RestoreStateIfNecessary(
166 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30167 const JavaParamRef<jstring>& j_persistence_id,
168 const JavaParamRef<jbyteArray>& j_persistence_crypto_key,
169 const JavaParamRef<jbyteArray>& j_minimal_persistence_state) {
Scott Violetb7df9d62020-01-31 16:18:49170 Browser::PersistenceInfo persistence_info;
171 Browser::PersistenceInfo* persistence_info_ptr = nullptr;
172
173 if (j_persistence_id.obj()) {
174 const std::string persistence_id =
175 base::android::ConvertJavaStringToUTF8(j_persistence_id);
176 if (!persistence_id.empty()) {
177 persistence_info.id = persistence_id;
178 if (j_persistence_crypto_key.obj()) {
179 base::android::JavaByteArrayToByteVector(
180 env, j_persistence_crypto_key, &(persistence_info.last_crypto_key));
181 }
182 persistence_info_ptr = &persistence_info;
183 }
184 } else if (j_minimal_persistence_state.obj()) {
185 base::android::JavaByteArrayToByteVector(env, j_minimal_persistence_state,
186 &(persistence_info.minimal_state));
187 persistence_info_ptr = &persistence_info;
188 }
189 if (persistence_info_ptr)
190 RestoreStateIfNecessary(*persistence_info_ptr);
191}
192
Bo Liu3362d482020-03-31 14:57:33193void BrowserImpl::WebPreferencesChanged(JNIEnv* env) {
194 for (const auto& tab : tabs_) {
195 TabImpl* tab_impl = static_cast<TabImpl*>(tab.get());
196 tab_impl->WebPreferencesChanged();
197 }
198}
Scott Violet1e3e0b42020-04-02 14:43:22199
Scott Violet0ccd63292020-05-03 02:32:45200void BrowserImpl::OnFragmentStart(JNIEnv* env) {
Scott Violet1e3e0b42020-04-02 14:43:22201 // FeatureListCreator is created before any Browsers.
202 DCHECK(FeatureListCreator::GetInstance());
203 FeatureListCreator::GetInstance()->OnBrowserFragmentStarted();
204}
205
Scott Violet009c09c2020-01-18 00:57:18206#endif
207
Scott Violet343f4ec2020-01-30 02:58:08208std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState(
209 int max_size_in_bytes) {
210 return PersistMinimalState(this, max_size_in_bytes);
211}
212
Bo Liuabea5dcc2020-04-20 16:06:23213void BrowserImpl::SetWebPreferences(content::WebPreferences* prefs) {
Bo Liu3362d482020-03-31 14:57:33214#if defined(OS_ANDROID)
Bo Liuabea5dcc2020-04-20 16:06:23215 prefs->password_echo_enabled = Java_BrowserImpl_getPasswordEchoEnabled(
216 AttachCurrentThread(), java_impl_);
217 prefs->preferred_color_scheme =
218 Java_BrowserImpl_getDarkThemeEnabled(AttachCurrentThread(), java_impl_)
219 ? blink::PreferredColorScheme::kDark
220 : blink::PreferredColorScheme::kLight;
Bo Liu3362d482020-03-31 14:57:33221#endif
222}
223
Scott Violetbb6c84552020-01-29 23:35:24224Tab* BrowserImpl::AddTab(std::unique_ptr<Tab> tab) {
Scott Violet009c09c2020-01-18 00:57:18225 DCHECK(tab);
Scott Violetbb6c84552020-01-29 23:35:24226 TabImpl* tab_impl = static_cast<TabImpl*>(tab.get());
227 DCHECK(!tab_impl->browser());
228 tabs_.push_back(std::move(tab));
Scott Violet009c09c2020-01-18 00:57:18229 tab_impl->set_browser(this);
230#if defined(OS_ANDROID)
Scott Violet90564152020-01-31 18:31:30231 Java_BrowserImpl_onTabAdded(AttachCurrentThread(), java_impl_,
Scott Violetbb6c84552020-01-29 23:35:24232 tab_impl->GetJavaTab());
Scott Violet009c09c2020-01-18 00:57:18233#endif
234 for (BrowserObserver& obs : browser_observers_)
Scott Violetbb6c84552020-01-29 23:35:24235 obs.OnTabAdded(tab_impl);
236 return tab_impl;
Scott Violet009c09c2020-01-18 00:57:18237}
238
Scott Violetbb6c84552020-01-29 23:35:24239std::unique_ptr<Tab> BrowserImpl::RemoveTab(Tab* tab) {
Scott Violet009c09c2020-01-18 00:57:18240 TabImpl* tab_impl = static_cast<TabImpl*>(tab);
241 DCHECK_EQ(this, tab_impl->browser());
242 static_cast<TabImpl*>(tab)->set_browser(nullptr);
Scott Violetbb6c84552020-01-29 23:35:24243 auto iter =
244 std::find_if(tabs_.begin(), tabs_.end(), base::MatchesUniquePtr(tab));
245 DCHECK(iter != tabs_.end());
246 std::unique_ptr<Tab> owned_tab = std::move(*iter);
247 tabs_.erase(iter);
Scott Violet009c09c2020-01-18 00:57:18248 const bool active_tab_changed = active_tab_ == tab;
249 if (active_tab_changed)
Scott Violet3e80a7b52020-04-10 13:57:40250 SetActiveTab(nullptr);
251
Scott Violet009c09c2020-01-18 00:57:18252#if defined(OS_ANDROID)
Scott Violet90564152020-01-31 18:31:30253 Java_BrowserImpl_onTabRemoved(AttachCurrentThread(), java_impl_,
Scott Violet009c09c2020-01-18 00:57:18254 tab ? tab_impl->GetJavaTab() : nullptr);
255#endif
Scott Violet009c09c2020-01-18 00:57:18256 for (BrowserObserver& obs : browser_observers_)
257 obs.OnTabRemoved(tab, active_tab_changed);
Scott Violetbb6c84552020-01-29 23:35:24258 return owned_tab;
Scott Violet009c09c2020-01-18 00:57:18259}
260
261void BrowserImpl::SetActiveTab(Tab* tab) {
262 if (GetActiveTab() == tab)
263 return;
Scott Violet3e80a7b52020-04-10 13:57:40264 if (active_tab_)
265 active_tab_->OnLosingActive();
Scott Violet009c09c2020-01-18 00:57:18266 // TODO: currently the java side sets visibility, this code likely should
267 // too and it should be removed from the java side.
268 active_tab_ = static_cast<TabImpl*>(tab);
269#if defined(OS_ANDROID)
270 Java_BrowserImpl_onActiveTabChanged(
Scott Violet90564152020-01-31 18:31:30271 AttachCurrentThread(), java_impl_,
Scott Violet009c09c2020-01-18 00:57:18272 active_tab_ ? active_tab_->GetJavaTab() : nullptr);
273#endif
Mugdha Lakhani4ee390d402020-04-07 18:41:00274 VisibleSecurityStateOfActiveTabChanged();
Scott Violet009c09c2020-01-18 00:57:18275 for (BrowserObserver& obs : browser_observers_)
276 obs.OnActiveTabChanged(active_tab_);
277 if (active_tab_)
278 active_tab_->web_contents()->GetController().LoadIfNecessary();
279}
280
281Tab* BrowserImpl::GetActiveTab() {
282 return active_tab_;
283}
284
Scott Violetbb6c84552020-01-29 23:35:24285std::vector<Tab*> BrowserImpl::GetTabs() {
286 std::vector<Tab*> tabs(tabs_.size());
287 for (size_t i = 0; i < tabs_.size(); ++i)
288 tabs[i] = tabs_[i].get();
289 return tabs;
Scott Violet009c09c2020-01-18 00:57:18290}
291
Scott Violet87450ce2020-01-23 01:56:25292void BrowserImpl::PrepareForShutdown() {
Scott Violet9843d0a2020-02-11 22:38:07293 browser_persister_.reset();
Scott Violet87450ce2020-01-23 01:56:25294}
295
Scott Violetbf8b8aa72020-01-28 19:37:32296std::string BrowserImpl::GetPersistenceId() {
Scott Violet58ad5a32020-01-23 22:07:27297 return persistence_id_;
298}
299
Scott Violet343f4ec2020-01-30 02:58:08300std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState() {
301 // 0 means use the default max.
302 return GetMinimalPersistenceState(0);
303}
304
Scott Violet009c09c2020-01-18 00:57:18305void BrowserImpl::AddObserver(BrowserObserver* observer) {
306 browser_observers_.AddObserver(observer);
307}
308
309void BrowserImpl::RemoveObserver(BrowserObserver* observer) {
310 browser_observers_.RemoveObserver(observer);
311}
312
Bo Liude377632020-02-10 19:23:49313BrowserImpl::BrowserImpl(ProfileImpl* profile) : profile_(profile) {
314 profile_->IncrementBrowserImplCount();
Tim Volodine9839f182020-04-23 17:51:25315 browser_count_++;
Bo Liude377632020-02-10 19:23:49316}
Scott Violetb7df9d62020-01-31 16:18:49317
318void BrowserImpl::RestoreStateIfNecessary(
319 const PersistenceInfo& persistence_info) {
320 persistence_id_ = persistence_info.id;
321 if (!persistence_id_.empty()) {
Scott Violet9843d0a2020-02-11 22:38:07322 browser_persister_ = std::make_unique<BrowserPersister>(
323 GetBrowserPersisterDataPath(), this, persistence_info.last_crypto_key);
Scott Violetb7df9d62020-01-31 16:18:49324 } else if (!persistence_info.minimal_state.empty()) {
325 RestoreMinimalState(this, persistence_info.minimal_state);
326 }
327}
328
Mugdha Lakhani9d858162020-01-31 21:12:04329void BrowserImpl::VisibleSecurityStateOfActiveTabChanged() {
Mugdha Lakhani5f8de7cc2020-03-10 20:43:36330 if (visible_security_state_changed_callback_for_tests_)
331 std::move(visible_security_state_changed_callback_for_tests_).Run();
332
Mugdha Lakhani9d858162020-01-31 21:12:04333#if defined(OS_ANDROID)
334 JNIEnv* env = base::android::AttachCurrentThread();
335 Java_BrowserImpl_onVisibleSecurityStateOfActiveTabChanged(env, java_impl_);
336#endif
337}
338
Scott Violet9843d0a2020-02-11 22:38:07339base::FilePath BrowserImpl::GetBrowserPersisterDataPath() {
340 base::FilePath base_path = profile_->GetBrowserPersisterDataBaseDir();
Scott Violetbf8b8aa72020-01-28 19:37:32341 DCHECK(!GetPersistenceId().empty());
342 const std::string encoded_name = base32::Base32Encode(GetPersistenceId());
Scott Violet87450ce2020-01-23 01:56:25343 return base_path.AppendASCII("State" + encoded_name);
344}
345
Scott Violetb7df9d62020-01-31 16:18:49346#if defined(OS_ANDROID)
347// This function is friended. JNI_BrowserImpl_CreateBrowser can not be
348// friended, as it requires browser_impl.h to include BrowserImpl_jni.h, which
349// is problematic (meaning not really supported and generates compile errors).
Scott Violet90564152020-01-31 18:31:30350BrowserImpl* CreateBrowserForAndroid(ProfileImpl* profile,
351 const JavaParamRef<jobject>& java_impl) {
Scott Violetb7df9d62020-01-31 16:18:49352 BrowserImpl* browser = new BrowserImpl(profile);
353 browser->java_impl_ = java_impl;
354 return browser;
Scott Violet87450ce2020-01-23 01:56:25355}
356
Scott Violet009c09c2020-01-18 00:57:18357static jlong JNI_BrowserImpl_CreateBrowser(
358 JNIEnv* env,
359 jlong profile,
Scott Violet90564152020-01-31 18:31:30360 const JavaParamRef<jobject>& java_impl) {
Scott Violetb7df9d62020-01-31 16:18:49361 // The android side does not trigger restore from the constructor as at the
362 // time this is called not enough of WebLayer has been wired up. Specifically,
363 // when this is called BrowserImpl.java hasn't obtained the return value so
364 // that it can't call any functions and further the client side hasn't been
365 // fully created, leading to all sort of assertions if Tabs are created
366 // and/or navigations start (which restore may trigger).
367 return reinterpret_cast<intptr_t>(CreateBrowserForAndroid(
368 reinterpret_cast<ProfileImpl*>(profile), java_impl));
Scott Violet009c09c2020-01-18 00:57:18369}
370
371static void JNI_BrowserImpl_DeleteBrowser(JNIEnv* env, jlong browser) {
372 delete reinterpret_cast<BrowserImpl*>(browser);
373}
374#endif
375
376} // namespace weblayer