blob: b8ef575d936bd3bd989996ba2388020037157c90 [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"
Scott Violet1e3e0b42020-04-02 14:43:2215#include "weblayer/browser/feature_list_creator.h"
Scott Violet9843d0a2020-02-11 22:38:0716#include "weblayer/browser/persistence/browser_persister.h"
Scott Violet343f4ec2020-01-30 02:58:0817#include "weblayer/browser/persistence/minimal_browser_persister.h"
Scott Violet009c09c2020-01-18 00:57:1818#include "weblayer/browser/profile_impl.h"
19#include "weblayer/browser/tab_impl.h"
Scott Violet87450ce2020-01-23 01:56:2520#include "weblayer/common/weblayer_paths.h"
Scott Violet009c09c2020-01-18 00:57:1821#include "weblayer/public/browser_observer.h"
22
23#if defined(OS_ANDROID)
24#include "base/android/callback_android.h"
Scott Violetbf8b8aa72020-01-28 19:37:3225#include "base/android/jni_array.h"
Scott Violet009c09c2020-01-18 00:57:1826#include "base/android/jni_string.h"
27#include "base/json/json_writer.h"
28#include "weblayer/browser/java/jni/BrowserImpl_jni.h"
29#endif
30
Scott Violet90564152020-01-31 18:31:3031#if defined(OS_ANDROID)
32using base::android::AttachCurrentThread;
33using base::android::JavaParamRef;
34using base::android::ScopedJavaLocalRef;
35#endif
36
Scott Violet009c09c2020-01-18 00:57:1837namespace weblayer {
38
Scott Violetbf8b8aa72020-01-28 19:37:3239std::unique_ptr<Browser> Browser::Create(
40 Profile* profile,
41 const PersistenceInfo* persistence_info) {
Scott Violetb7df9d62020-01-31 16:18:4942 // BrowserImpl's constructor is private.
43 auto browser =
44 base::WrapUnique(new BrowserImpl(static_cast<ProfileImpl*>(profile)));
Scott Violetbf8b8aa72020-01-28 19:37:3245 if (persistence_info)
Scott Violetb7df9d62020-01-31 16:18:4946 browser->RestoreStateIfNecessary(*persistence_info);
47 return browser;
Scott Violet87450ce2020-01-23 01:56:2548}
Scott Violet009c09c2020-01-18 00:57:1849
50BrowserImpl::~BrowserImpl() {
Scott Violetbb6c84552020-01-29 23:35:2451#if defined(OS_ANDROID)
52 // Android side should always remove tabs first (because the Java Tab class
53 // owns the C++ Tab). See BrowserImpl.destroy() (in the Java BrowserImpl
54 // class).
55 DCHECK(tabs_.empty());
56#else
57 while (!tabs_.empty())
58 RemoveTab(tabs_.back().get());
59#endif
Bo Liude377632020-02-10 19:23:4960 profile_->DecrementBrowserImplCount();
Scott Violet009c09c2020-01-18 00:57:1861}
62
Scott Violet58ad5a32020-01-23 22:07:2763TabImpl* BrowserImpl::CreateTabForSessionRestore(
Scott Violetb2e0cf12020-03-09 18:46:4364 std::unique_ptr<content::WebContents> web_contents,
65 const std::string& guid) {
Scott Violetbb6c84552020-01-29 23:35:2466 std::unique_ptr<TabImpl> tab =
Scott Violetb2e0cf12020-03-09 18:46:4367 std::make_unique<TabImpl>(profile_, std::move(web_contents), guid);
Scott Violet58ad5a32020-01-23 22:07:2768#if defined(OS_ANDROID)
Scott Violet58ad5a32020-01-23 22:07:2769 Java_BrowserImpl_createTabForSessionRestore(
Scott Violet90564152020-01-31 18:31:3070 AttachCurrentThread(), java_impl_, reinterpret_cast<jlong>(tab.get()));
Scott Violet58ad5a32020-01-23 22:07:2771#endif
Scott Violetbb6c84552020-01-29 23:35:2472 TabImpl* tab_ptr = tab.get();
73 AddTab(std::move(tab));
74 return tab_ptr;
Scott Violet58ad5a32020-01-23 22:07:2775}
76
Scott Violet009c09c2020-01-18 00:57:1877#if defined(OS_ANDROID)
78void BrowserImpl::AddTab(JNIEnv* env,
Scott Violet90564152020-01-31 18:31:3079 const JavaParamRef<jobject>& caller,
Scott Violet009c09c2020-01-18 00:57:1880 long native_tab) {
Scott Violetbb6c84552020-01-29 23:35:2481 TabImpl* tab = reinterpret_cast<TabImpl*>(native_tab);
82 std::unique_ptr<Tab> owned_tab;
83 if (tab->browser())
84 owned_tab = tab->browser()->RemoveTab(tab);
85 else
86 owned_tab.reset(tab);
87 AddTab(std::move(owned_tab));
Scott Violet009c09c2020-01-18 00:57:1888}
89
90void BrowserImpl::RemoveTab(JNIEnv* env,
Scott Violet90564152020-01-31 18:31:3091 const JavaParamRef<jobject>& caller,
Scott Violet009c09c2020-01-18 00:57:1892 long native_tab) {
Scott Violetbb6c84552020-01-29 23:35:2493 // The Java side owns the Tab.
94 RemoveTab(reinterpret_cast<TabImpl*>(native_tab)).release();
Scott Violet009c09c2020-01-18 00:57:1895}
96
Scott Violet90564152020-01-31 18:31:3097ScopedJavaLocalRef<jobjectArray> BrowserImpl::GetTabs(
Scott Violet009c09c2020-01-18 00:57:1898 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:3099 const JavaParamRef<jobject>& caller) {
100 ScopedJavaLocalRef<jclass> clazz =
Scott Violet009c09c2020-01-18 00:57:18101 base::android::GetClass(env, "org/chromium/weblayer_private/TabImpl");
102 jobjectArray tabs = env->NewObjectArray(tabs_.size(), clazz.obj(),
103 nullptr /* initialElement */);
104 base::android::CheckException(env);
105
106 for (size_t i = 0; i < tabs_.size(); ++i) {
Scott Violetbb6c84552020-01-29 23:35:24107 TabImpl* tab = static_cast<TabImpl*>(tabs_[i].get());
Scott Violet009c09c2020-01-18 00:57:18108 env->SetObjectArrayElement(tabs, i, tab->GetJavaTab().obj());
109 }
Scott Violet90564152020-01-31 18:31:30110 return ScopedJavaLocalRef<jobjectArray>(env, tabs);
Scott Violet009c09c2020-01-18 00:57:18111}
112
Scott Violet90564152020-01-31 18:31:30113void BrowserImpl::SetActiveTab(JNIEnv* env,
114 const JavaParamRef<jobject>& caller,
115 long native_tab) {
Scott Violet009c09c2020-01-18 00:57:18116 SetActiveTab(reinterpret_cast<TabImpl*>(native_tab));
117}
118
Scott Violet90564152020-01-31 18:31:30119ScopedJavaLocalRef<jobject> BrowserImpl::GetActiveTab(
Scott Violet009c09c2020-01-18 00:57:18120 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30121 const JavaParamRef<jobject>& caller) {
Scott Violet009c09c2020-01-18 00:57:18122 if (!active_tab_)
123 return nullptr;
Scott Violet90564152020-01-31 18:31:30124 return ScopedJavaLocalRef<jobject>(active_tab_->GetJavaTab());
Scott Violet009c09c2020-01-18 00:57:18125}
Scott Violet58ad5a32020-01-23 22:07:27126
Scott Violet90564152020-01-31 18:31:30127void BrowserImpl::PrepareForShutdown(JNIEnv* env,
128 const JavaParamRef<jobject>& caller) {
Scott Violet58ad5a32020-01-23 22:07:27129 PrepareForShutdown();
130}
131
Scott Violet90564152020-01-31 18:31:30132ScopedJavaLocalRef<jstring> BrowserImpl::GetPersistenceId(
Scott Violet58ad5a32020-01-23 22:07:27133 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30134 const JavaParamRef<jobject>& caller) {
135 return ScopedJavaLocalRef<jstring>(
Scott Violetbf8b8aa72020-01-28 19:37:32136 base::android::ConvertUTF8ToJavaString(env, GetPersistenceId()));
137}
138
Scott Violet9843d0a2020-02-11 22:38:07139void BrowserImpl::SaveBrowserPersisterIfNecessary(
Scott Violetbf8b8aa72020-01-28 19:37:32140 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30141 const JavaParamRef<jobject>& caller) {
Scott Violet9843d0a2020-02-11 22:38:07142 browser_persister_->SaveIfNecessary();
Scott Violetbf8b8aa72020-01-28 19:37:32143}
144
Scott Violet9843d0a2020-02-11 22:38:07145ScopedJavaLocalRef<jbyteArray> BrowserImpl::GetBrowserPersisterCryptoKey(
Scott Violetbf8b8aa72020-01-28 19:37:32146 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30147 const JavaParamRef<jobject>& caller) {
Scott Violetbf8b8aa72020-01-28 19:37:32148 std::vector<uint8_t> key;
Scott Violet9843d0a2020-02-11 22:38:07149 if (browser_persister_)
150 key = browser_persister_->GetCryptoKey();
Scott Violetbf8b8aa72020-01-28 19:37:32151 return base::android::ToJavaByteArray(env, key);
Scott Violet58ad5a32020-01-23 22:07:27152}
153
Scott Violet90564152020-01-31 18:31:30154ScopedJavaLocalRef<jbyteArray> BrowserImpl::GetMinimalPersistenceState(
Scott Violet343f4ec2020-01-30 02:58:08155 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30156 const JavaParamRef<jobject>& caller) {
Scott Violet343f4ec2020-01-30 02:58:08157 auto state = GetMinimalPersistenceState();
158 return base::android::ToJavaByteArray(env, &(state.front()), state.size());
159}
160
Scott Violetb7df9d62020-01-31 16:18:49161void BrowserImpl::RestoreStateIfNecessary(
162 JNIEnv* env,
Scott Violet90564152020-01-31 18:31:30163 const JavaParamRef<jobject>& caller,
164 const JavaParamRef<jstring>& j_persistence_id,
165 const JavaParamRef<jbyteArray>& j_persistence_crypto_key,
166 const JavaParamRef<jbyteArray>& j_minimal_persistence_state) {
Scott Violetb7df9d62020-01-31 16:18:49167 Browser::PersistenceInfo persistence_info;
168 Browser::PersistenceInfo* persistence_info_ptr = nullptr;
169
170 if (j_persistence_id.obj()) {
171 const std::string persistence_id =
172 base::android::ConvertJavaStringToUTF8(j_persistence_id);
173 if (!persistence_id.empty()) {
174 persistence_info.id = persistence_id;
175 if (j_persistence_crypto_key.obj()) {
176 base::android::JavaByteArrayToByteVector(
177 env, j_persistence_crypto_key, &(persistence_info.last_crypto_key));
178 }
179 persistence_info_ptr = &persistence_info;
180 }
181 } else if (j_minimal_persistence_state.obj()) {
182 base::android::JavaByteArrayToByteVector(env, j_minimal_persistence_state,
183 &(persistence_info.minimal_state));
184 persistence_info_ptr = &persistence_info;
185 }
186 if (persistence_info_ptr)
187 RestoreStateIfNecessary(*persistence_info_ptr);
188}
189
Bo Liu3362d482020-03-31 14:57:33190void BrowserImpl::WebPreferencesChanged(JNIEnv* env) {
191 for (const auto& tab : tabs_) {
192 TabImpl* tab_impl = static_cast<TabImpl*>(tab.get());
193 tab_impl->WebPreferencesChanged();
194 }
195}
Scott Violet1e3e0b42020-04-02 14:43:22196
197void BrowserImpl::OnFragmentStart(
198 JNIEnv* env,
199 const base::android::JavaParamRef<jobject>& caller) {
200 // FeatureListCreator is created before any Browsers.
201 DCHECK(FeatureListCreator::GetInstance());
202 FeatureListCreator::GetInstance()->OnBrowserFragmentStarted();
203}
204
Scott Violet009c09c2020-01-18 00:57:18205#endif
206
Scott Violet343f4ec2020-01-30 02:58:08207std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState(
208 int max_size_in_bytes) {
209 return PersistMinimalState(this, max_size_in_bytes);
210}
211
Bo Liu3362d482020-03-31 14:57:33212bool BrowserImpl::GetPasswordEchoEnabled() {
213#if defined(OS_ANDROID)
214 return Java_BrowserImpl_getPasswordEchoEnabled(AttachCurrentThread(),
215 java_impl_);
216#else
217 return false;
218#endif
219}
220
Scott Violetbb6c84552020-01-29 23:35:24221Tab* BrowserImpl::AddTab(std::unique_ptr<Tab> tab) {
Scott Violet009c09c2020-01-18 00:57:18222 DCHECK(tab);
Scott Violetbb6c84552020-01-29 23:35:24223 TabImpl* tab_impl = static_cast<TabImpl*>(tab.get());
224 DCHECK(!tab_impl->browser());
225 tabs_.push_back(std::move(tab));
Scott Violet009c09c2020-01-18 00:57:18226 tab_impl->set_browser(this);
227#if defined(OS_ANDROID)
Scott Violet90564152020-01-31 18:31:30228 Java_BrowserImpl_onTabAdded(AttachCurrentThread(), java_impl_,
Scott Violetbb6c84552020-01-29 23:35:24229 tab_impl->GetJavaTab());
Scott Violet009c09c2020-01-18 00:57:18230#endif
231 for (BrowserObserver& obs : browser_observers_)
Scott Violetbb6c84552020-01-29 23:35:24232 obs.OnTabAdded(tab_impl);
233 return tab_impl;
Scott Violet009c09c2020-01-18 00:57:18234}
235
Scott Violetbb6c84552020-01-29 23:35:24236std::unique_ptr<Tab> BrowserImpl::RemoveTab(Tab* tab) {
Scott Violet009c09c2020-01-18 00:57:18237 TabImpl* tab_impl = static_cast<TabImpl*>(tab);
238 DCHECK_EQ(this, tab_impl->browser());
239 static_cast<TabImpl*>(tab)->set_browser(nullptr);
Scott Violetbb6c84552020-01-29 23:35:24240 auto iter =
241 std::find_if(tabs_.begin(), tabs_.end(), base::MatchesUniquePtr(tab));
242 DCHECK(iter != tabs_.end());
243 std::unique_ptr<Tab> owned_tab = std::move(*iter);
244 tabs_.erase(iter);
Scott Violet009c09c2020-01-18 00:57:18245 const bool active_tab_changed = active_tab_ == tab;
246 if (active_tab_changed)
Scott Violet3e80a7b52020-04-10 13:57:40247 SetActiveTab(nullptr);
248
Scott Violet009c09c2020-01-18 00:57:18249#if defined(OS_ANDROID)
Scott Violet90564152020-01-31 18:31:30250 Java_BrowserImpl_onTabRemoved(AttachCurrentThread(), java_impl_,
Scott Violet009c09c2020-01-18 00:57:18251 tab ? tab_impl->GetJavaTab() : nullptr);
252#endif
Scott Violet009c09c2020-01-18 00:57:18253 for (BrowserObserver& obs : browser_observers_)
254 obs.OnTabRemoved(tab, active_tab_changed);
Scott Violetbb6c84552020-01-29 23:35:24255 return owned_tab;
Scott Violet009c09c2020-01-18 00:57:18256}
257
258void BrowserImpl::SetActiveTab(Tab* tab) {
259 if (GetActiveTab() == tab)
260 return;
Scott Violet3e80a7b52020-04-10 13:57:40261 if (active_tab_)
262 active_tab_->OnLosingActive();
Scott Violet009c09c2020-01-18 00:57:18263 // TODO: currently the java side sets visibility, this code likely should
264 // too and it should be removed from the java side.
265 active_tab_ = static_cast<TabImpl*>(tab);
266#if defined(OS_ANDROID)
267 Java_BrowserImpl_onActiveTabChanged(
Scott Violet90564152020-01-31 18:31:30268 AttachCurrentThread(), java_impl_,
Scott Violet009c09c2020-01-18 00:57:18269 active_tab_ ? active_tab_->GetJavaTab() : nullptr);
270#endif
Mugdha Lakhani4ee390d402020-04-07 18:41:00271 VisibleSecurityStateOfActiveTabChanged();
Scott Violet009c09c2020-01-18 00:57:18272 for (BrowserObserver& obs : browser_observers_)
273 obs.OnActiveTabChanged(active_tab_);
274 if (active_tab_)
275 active_tab_->web_contents()->GetController().LoadIfNecessary();
276}
277
278Tab* BrowserImpl::GetActiveTab() {
279 return active_tab_;
280}
281
Scott Violetbb6c84552020-01-29 23:35:24282std::vector<Tab*> BrowserImpl::GetTabs() {
283 std::vector<Tab*> tabs(tabs_.size());
284 for (size_t i = 0; i < tabs_.size(); ++i)
285 tabs[i] = tabs_[i].get();
286 return tabs;
Scott Violet009c09c2020-01-18 00:57:18287}
288
Scott Violet87450ce2020-01-23 01:56:25289void BrowserImpl::PrepareForShutdown() {
Scott Violet9843d0a2020-02-11 22:38:07290 browser_persister_.reset();
Scott Violet87450ce2020-01-23 01:56:25291}
292
Scott Violetbf8b8aa72020-01-28 19:37:32293std::string BrowserImpl::GetPersistenceId() {
Scott Violet58ad5a32020-01-23 22:07:27294 return persistence_id_;
295}
296
Scott Violet343f4ec2020-01-30 02:58:08297std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState() {
298 // 0 means use the default max.
299 return GetMinimalPersistenceState(0);
300}
301
Scott Violet009c09c2020-01-18 00:57:18302void BrowserImpl::AddObserver(BrowserObserver* observer) {
303 browser_observers_.AddObserver(observer);
304}
305
306void BrowserImpl::RemoveObserver(BrowserObserver* observer) {
307 browser_observers_.RemoveObserver(observer);
308}
309
Bo Liude377632020-02-10 19:23:49310BrowserImpl::BrowserImpl(ProfileImpl* profile) : profile_(profile) {
311 profile_->IncrementBrowserImplCount();
312}
Scott Violetb7df9d62020-01-31 16:18:49313
314void BrowserImpl::RestoreStateIfNecessary(
315 const PersistenceInfo& persistence_info) {
316 persistence_id_ = persistence_info.id;
317 if (!persistence_id_.empty()) {
Scott Violet9843d0a2020-02-11 22:38:07318 browser_persister_ = std::make_unique<BrowserPersister>(
319 GetBrowserPersisterDataPath(), this, persistence_info.last_crypto_key);
Scott Violetb7df9d62020-01-31 16:18:49320 } else if (!persistence_info.minimal_state.empty()) {
321 RestoreMinimalState(this, persistence_info.minimal_state);
322 }
323}
324
Mugdha Lakhani9d858162020-01-31 21:12:04325void BrowserImpl::VisibleSecurityStateOfActiveTabChanged() {
Mugdha Lakhani5f8de7cc2020-03-10 20:43:36326 if (visible_security_state_changed_callback_for_tests_)
327 std::move(visible_security_state_changed_callback_for_tests_).Run();
328
Mugdha Lakhani9d858162020-01-31 21:12:04329#if defined(OS_ANDROID)
330 JNIEnv* env = base::android::AttachCurrentThread();
331 Java_BrowserImpl_onVisibleSecurityStateOfActiveTabChanged(env, java_impl_);
332#endif
333}
334
Scott Violet9843d0a2020-02-11 22:38:07335base::FilePath BrowserImpl::GetBrowserPersisterDataPath() {
336 base::FilePath base_path = profile_->GetBrowserPersisterDataBaseDir();
Scott Violetbf8b8aa72020-01-28 19:37:32337 DCHECK(!GetPersistenceId().empty());
338 const std::string encoded_name = base32::Base32Encode(GetPersistenceId());
Scott Violet87450ce2020-01-23 01:56:25339 return base_path.AppendASCII("State" + encoded_name);
340}
341
Scott Violetb7df9d62020-01-31 16:18:49342#if defined(OS_ANDROID)
343// This function is friended. JNI_BrowserImpl_CreateBrowser can not be
344// friended, as it requires browser_impl.h to include BrowserImpl_jni.h, which
345// is problematic (meaning not really supported and generates compile errors).
Scott Violet90564152020-01-31 18:31:30346BrowserImpl* CreateBrowserForAndroid(ProfileImpl* profile,
347 const JavaParamRef<jobject>& java_impl) {
Scott Violetb7df9d62020-01-31 16:18:49348 BrowserImpl* browser = new BrowserImpl(profile);
349 browser->java_impl_ = java_impl;
350 return browser;
Scott Violet87450ce2020-01-23 01:56:25351}
352
Scott Violet009c09c2020-01-18 00:57:18353static jlong JNI_BrowserImpl_CreateBrowser(
354 JNIEnv* env,
355 jlong profile,
Scott Violet90564152020-01-31 18:31:30356 const JavaParamRef<jobject>& java_impl) {
Scott Violetb7df9d62020-01-31 16:18:49357 // The android side does not trigger restore from the constructor as at the
358 // time this is called not enough of WebLayer has been wired up. Specifically,
359 // when this is called BrowserImpl.java hasn't obtained the return value so
360 // that it can't call any functions and further the client side hasn't been
361 // fully created, leading to all sort of assertions if Tabs are created
362 // and/or navigations start (which restore may trigger).
363 return reinterpret_cast<intptr_t>(CreateBrowserForAndroid(
364 reinterpret_cast<ProfileImpl*>(profile), java_impl));
Scott Violet009c09c2020-01-18 00:57:18365}
366
367static void JNI_BrowserImpl_DeleteBrowser(JNIEnv* env, jlong browser) {
368 delete reinterpret_cast<BrowserImpl*>(browser);
369}
370#endif
371
372} // namespace weblayer