blob: 26020616359e8c88bea78142bfe56e4a863af41f [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
Scott Violetbb6c84552020-01-29 23:35:249#include "base/containers/unique_ptr_adapters.h"
Scott Violet87450ce2020-01-23 01:56:2510#include "base/path_service.h"
11#include "components/base32/base32.h"
12#include "content/public/browser/browser_context.h"
Scott Violet343f4ec2020-01-30 02:58:0813#include "weblayer/browser/persistence/minimal_browser_persister.h"
Scott Violet009c09c2020-01-18 00:57:1814#include "weblayer/browser/profile_impl.h"
Scott Violet87450ce2020-01-23 01:56:2515#include "weblayer/browser/session_service.h"
Scott Violet009c09c2020-01-18 00:57:1816#include "weblayer/browser/tab_impl.h"
Scott Violet87450ce2020-01-23 01:56:2517#include "weblayer/common/weblayer_paths.h"
Scott Violet009c09c2020-01-18 00:57:1818#include "weblayer/public/browser_observer.h"
19
20#if defined(OS_ANDROID)
21#include "base/android/callback_android.h"
Scott Violetbf8b8aa72020-01-28 19:37:3222#include "base/android/jni_array.h"
Scott Violet009c09c2020-01-18 00:57:1823#include "base/android/jni_string.h"
24#include "base/json/json_writer.h"
25#include "weblayer/browser/java/jni/BrowserImpl_jni.h"
26#endif
27
28namespace weblayer {
29
Scott Violetbf8b8aa72020-01-28 19:37:3230std::unique_ptr<Browser> Browser::Create(
31 Profile* profile,
32 const PersistenceInfo* persistence_info) {
Scott Violet87450ce2020-01-23 01:56:2533 return std::make_unique<BrowserImpl>(static_cast<ProfileImpl*>(profile),
Scott Violetbf8b8aa72020-01-28 19:37:3234 persistence_info);
Scott Violet009c09c2020-01-18 00:57:1835}
36
37#if defined(OS_ANDROID)
38BrowserImpl::BrowserImpl(ProfileImpl* profile,
Scott Violetbf8b8aa72020-01-28 19:37:3239 const PersistenceInfo* persistence_info,
Scott Violet009c09c2020-01-18 00:57:1840 const base::android::JavaParamRef<jobject>& java_impl)
Scott Violetbf8b8aa72020-01-28 19:37:3241 : BrowserImpl(profile, persistence_info) {
Scott Violet009c09c2020-01-18 00:57:1842 java_impl_ = java_impl;
43}
44#endif
45
Scott Violet87450ce2020-01-23 01:56:2546BrowserImpl::BrowserImpl(ProfileImpl* profile,
Scott Violetbf8b8aa72020-01-28 19:37:3247 const PersistenceInfo* persistence_info)
48 : profile_(profile),
49 persistence_id_(persistence_info ? persistence_info->id : std::string()) {
50 if (persistence_info)
Scott Violet343f4ec2020-01-30 02:58:0851 RestoreStateIfNecessary(*persistence_info);
Scott Violet87450ce2020-01-23 01:56:2552}
Scott Violet009c09c2020-01-18 00:57:1853
54BrowserImpl::~BrowserImpl() {
Scott Violetbb6c84552020-01-29 23:35:2455#if defined(OS_ANDROID)
56 // Android side should always remove tabs first (because the Java Tab class
57 // owns the C++ Tab). See BrowserImpl.destroy() (in the Java BrowserImpl
58 // class).
59 DCHECK(tabs_.empty());
60#else
61 while (!tabs_.empty())
62 RemoveTab(tabs_.back().get());
63#endif
Scott Violet009c09c2020-01-18 00:57:1864}
65
Scott Violet58ad5a32020-01-23 22:07:2766TabImpl* BrowserImpl::CreateTabForSessionRestore(
67 std::unique_ptr<content::WebContents> web_contents) {
Scott Violetbb6c84552020-01-29 23:35:2468 std::unique_ptr<TabImpl> tab =
69 std::make_unique<TabImpl>(profile_, std::move(web_contents));
Scott Violet58ad5a32020-01-23 22:07:2770#if defined(OS_ANDROID)
Scott Violet58ad5a32020-01-23 22:07:2771 Java_BrowserImpl_createTabForSessionRestore(
72 base::android::AttachCurrentThread(), java_impl_,
Scott Violetbb6c84552020-01-29 23:35:2473 reinterpret_cast<jlong>(tab.get()));
Scott Violet58ad5a32020-01-23 22:07:2774#endif
Scott Violetbb6c84552020-01-29 23:35:2475 TabImpl* tab_ptr = tab.get();
76 AddTab(std::move(tab));
77 return tab_ptr;
Scott Violet58ad5a32020-01-23 22:07:2778}
79
Scott Violet009c09c2020-01-18 00:57:1880#if defined(OS_ANDROID)
81void BrowserImpl::AddTab(JNIEnv* env,
82 const base::android::JavaParamRef<jobject>& caller,
83 long native_tab) {
Scott Violetbb6c84552020-01-29 23:35:2484 TabImpl* tab = reinterpret_cast<TabImpl*>(native_tab);
85 std::unique_ptr<Tab> owned_tab;
86 if (tab->browser())
87 owned_tab = tab->browser()->RemoveTab(tab);
88 else
89 owned_tab.reset(tab);
90 AddTab(std::move(owned_tab));
Scott Violet009c09c2020-01-18 00:57:1891}
92
93void BrowserImpl::RemoveTab(JNIEnv* env,
94 const base::android::JavaParamRef<jobject>& caller,
95 long native_tab) {
Scott Violetbb6c84552020-01-29 23:35:2496 // The Java side owns the Tab.
97 RemoveTab(reinterpret_cast<TabImpl*>(native_tab)).release();
Scott Violet009c09c2020-01-18 00:57:1898}
99
100base::android::ScopedJavaLocalRef<jobjectArray> BrowserImpl::GetTabs(
101 JNIEnv* env,
102 const base::android::JavaParamRef<jobject>& caller) {
103 base::android::ScopedJavaLocalRef<jclass> clazz =
104 base::android::GetClass(env, "org/chromium/weblayer_private/TabImpl");
105 jobjectArray tabs = env->NewObjectArray(tabs_.size(), clazz.obj(),
106 nullptr /* initialElement */);
107 base::android::CheckException(env);
108
109 for (size_t i = 0; i < tabs_.size(); ++i) {
Scott Violetbb6c84552020-01-29 23:35:24110 TabImpl* tab = static_cast<TabImpl*>(tabs_[i].get());
Scott Violet009c09c2020-01-18 00:57:18111 env->SetObjectArrayElement(tabs, i, tab->GetJavaTab().obj());
112 }
113 return base::android::ScopedJavaLocalRef<jobjectArray>(env, tabs);
114}
115
116void BrowserImpl::SetActiveTab(
117 JNIEnv* env,
118 const base::android::JavaParamRef<jobject>& caller,
119 long native_tab) {
120 SetActiveTab(reinterpret_cast<TabImpl*>(native_tab));
121}
122
123base::android::ScopedJavaLocalRef<jobject> BrowserImpl::GetActiveTab(
124 JNIEnv* env,
125 const base::android::JavaParamRef<jobject>& caller) {
126 if (!active_tab_)
127 return nullptr;
128 return base::android::ScopedJavaLocalRef<jobject>(active_tab_->GetJavaTab());
129}
Scott Violet58ad5a32020-01-23 22:07:27130
131void BrowserImpl::PrepareForShutdown(
132 JNIEnv* env,
133 const base::android::JavaParamRef<jobject>& caller) {
134 PrepareForShutdown();
135}
136
137base::android::ScopedJavaLocalRef<jstring> BrowserImpl::GetPersistenceId(
138 JNIEnv* env,
139 const base::android::JavaParamRef<jobject>& caller) {
140 return base::android::ScopedJavaLocalRef<jstring>(
Scott Violetbf8b8aa72020-01-28 19:37:32141 base::android::ConvertUTF8ToJavaString(env, GetPersistenceId()));
142}
143
144void BrowserImpl::SaveSessionServiceIfNecessary(
145 JNIEnv* env,
146 const base::android::JavaParamRef<jobject>& caller) {
147 session_service_->SaveIfNecessary();
148}
149
150base::android::ScopedJavaLocalRef<jbyteArray>
151BrowserImpl::GetSessionServiceCryptoKey(
152 JNIEnv* env,
153 const base::android::JavaParamRef<jobject>& caller) {
154 std::vector<uint8_t> key;
155 if (session_service_)
156 key = session_service_->GetCryptoKey();
157 return base::android::ToJavaByteArray(env, key);
Scott Violet58ad5a32020-01-23 22:07:27158}
159
Scott Violet343f4ec2020-01-30 02:58:08160base::android::ScopedJavaLocalRef<jbyteArray>
161BrowserImpl::GetMinimalPersistenceState(
162 JNIEnv* env,
163 const base::android::JavaParamRef<jobject>& caller) {
164 auto state = GetMinimalPersistenceState();
165 return base::android::ToJavaByteArray(env, &(state.front()), state.size());
166}
167
Scott Violet009c09c2020-01-18 00:57:18168#endif
169
Scott Violet343f4ec2020-01-30 02:58:08170std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState(
171 int max_size_in_bytes) {
172 return PersistMinimalState(this, max_size_in_bytes);
173}
174
Scott Violetbb6c84552020-01-29 23:35:24175Tab* BrowserImpl::AddTab(std::unique_ptr<Tab> tab) {
Scott Violet009c09c2020-01-18 00:57:18176 DCHECK(tab);
Scott Violetbb6c84552020-01-29 23:35:24177 TabImpl* tab_impl = static_cast<TabImpl*>(tab.get());
178 DCHECK(!tab_impl->browser());
179 tabs_.push_back(std::move(tab));
Scott Violet009c09c2020-01-18 00:57:18180 tab_impl->set_browser(this);
181#if defined(OS_ANDROID)
182 Java_BrowserImpl_onTabAdded(base::android::AttachCurrentThread(), java_impl_,
Scott Violetbb6c84552020-01-29 23:35:24183 tab_impl->GetJavaTab());
Scott Violet009c09c2020-01-18 00:57:18184#endif
185 for (BrowserObserver& obs : browser_observers_)
Scott Violetbb6c84552020-01-29 23:35:24186 obs.OnTabAdded(tab_impl);
187 return tab_impl;
Scott Violet009c09c2020-01-18 00:57:18188}
189
Scott Violetbb6c84552020-01-29 23:35:24190std::unique_ptr<Tab> BrowserImpl::RemoveTab(Tab* tab) {
Scott Violet009c09c2020-01-18 00:57:18191 TabImpl* tab_impl = static_cast<TabImpl*>(tab);
192 DCHECK_EQ(this, tab_impl->browser());
193 static_cast<TabImpl*>(tab)->set_browser(nullptr);
Scott Violetbb6c84552020-01-29 23:35:24194 auto iter =
195 std::find_if(tabs_.begin(), tabs_.end(), base::MatchesUniquePtr(tab));
196 DCHECK(iter != tabs_.end());
197 std::unique_ptr<Tab> owned_tab = std::move(*iter);
198 tabs_.erase(iter);
Scott Violet009c09c2020-01-18 00:57:18199 const bool active_tab_changed = active_tab_ == tab;
200 if (active_tab_changed)
201 active_tab_ = nullptr;
202#if defined(OS_ANDROID)
203 if (active_tab_changed) {
204 Java_BrowserImpl_onActiveTabChanged(
205 base::android::AttachCurrentThread(), java_impl_,
206 active_tab_ ? static_cast<TabImpl*>(active_tab_)->GetJavaTab()
207 : nullptr);
208 }
209 Java_BrowserImpl_onTabRemoved(base::android::AttachCurrentThread(),
210 java_impl_,
211 tab ? tab_impl->GetJavaTab() : nullptr);
212#endif
213 if (active_tab_changed) {
214 for (BrowserObserver& obs : browser_observers_)
215 obs.OnActiveTabChanged(active_tab_);
216 }
217 for (BrowserObserver& obs : browser_observers_)
218 obs.OnTabRemoved(tab, active_tab_changed);
Scott Violetbb6c84552020-01-29 23:35:24219 return owned_tab;
Scott Violet009c09c2020-01-18 00:57:18220}
221
222void BrowserImpl::SetActiveTab(Tab* tab) {
223 if (GetActiveTab() == tab)
224 return;
225 // TODO: currently the java side sets visibility, this code likely should
226 // too and it should be removed from the java side.
227 active_tab_ = static_cast<TabImpl*>(tab);
228#if defined(OS_ANDROID)
229 Java_BrowserImpl_onActiveTabChanged(
230 base::android::AttachCurrentThread(), java_impl_,
231 active_tab_ ? active_tab_->GetJavaTab() : nullptr);
232#endif
233 for (BrowserObserver& obs : browser_observers_)
234 obs.OnActiveTabChanged(active_tab_);
235 if (active_tab_)
236 active_tab_->web_contents()->GetController().LoadIfNecessary();
237}
238
239Tab* BrowserImpl::GetActiveTab() {
240 return active_tab_;
241}
242
Scott Violetbb6c84552020-01-29 23:35:24243std::vector<Tab*> BrowserImpl::GetTabs() {
244 std::vector<Tab*> tabs(tabs_.size());
245 for (size_t i = 0; i < tabs_.size(); ++i)
246 tabs[i] = tabs_[i].get();
247 return tabs;
Scott Violet009c09c2020-01-18 00:57:18248}
249
Scott Violet87450ce2020-01-23 01:56:25250void BrowserImpl::PrepareForShutdown() {
251 session_service_.reset();
252}
253
Scott Violetbf8b8aa72020-01-28 19:37:32254std::string BrowserImpl::GetPersistenceId() {
Scott Violet58ad5a32020-01-23 22:07:27255 return persistence_id_;
256}
257
Scott Violet343f4ec2020-01-30 02:58:08258std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState() {
259 // 0 means use the default max.
260 return GetMinimalPersistenceState(0);
261}
262
Scott Violet009c09c2020-01-18 00:57:18263void BrowserImpl::AddObserver(BrowserObserver* observer) {
264 browser_observers_.AddObserver(observer);
265}
266
267void BrowserImpl::RemoveObserver(BrowserObserver* observer) {
268 browser_observers_.RemoveObserver(observer);
269}
270
Scott Violet87450ce2020-01-23 01:56:25271base::FilePath BrowserImpl::GetSessionServiceDataPath() {
272 base::FilePath base_path;
273 if (profile_->GetBrowserContext()->IsOffTheRecord()) {
274 CHECK(base::PathService::Get(DIR_USER_DATA, &base_path));
275 base_path = base_path.AppendASCII("Incognito Restore Data");
276 } else {
277 base_path = profile_->data_path().AppendASCII("Restore Data");
278 }
Scott Violetbf8b8aa72020-01-28 19:37:32279 DCHECK(!GetPersistenceId().empty());
280 const std::string encoded_name = base32::Base32Encode(GetPersistenceId());
Scott Violet87450ce2020-01-23 01:56:25281 return base_path.AppendASCII("State" + encoded_name);
282}
283
Scott Violet343f4ec2020-01-30 02:58:08284void BrowserImpl::RestoreStateIfNecessary(
Scott Violetbf8b8aa72020-01-28 19:37:32285 const PersistenceInfo& persistence_info) {
Scott Violet343f4ec2020-01-30 02:58:08286 if (!persistence_info.id.empty()) {
287 session_service_ = std::make_unique<SessionService>(
288 GetSessionServiceDataPath(), this, persistence_info.last_crypto_key);
289 } else if (!persistence_info.minimal_state.empty()) {
290 RestoreMinimalState(this, persistence_info.minimal_state);
291 }
Scott Violet87450ce2020-01-23 01:56:25292}
293
Scott Violet009c09c2020-01-18 00:57:18294#if defined(OS_ANDROID)
295static jlong JNI_BrowserImpl_CreateBrowser(
296 JNIEnv* env,
297 jlong profile,
Scott Violetbf8b8aa72020-01-28 19:37:32298 const base::android::JavaParamRef<jstring>& j_persistence_id,
299 const base::android::JavaParamRef<jbyteArray>& j_persistence_crypto_key,
Scott Violet009c09c2020-01-18 00:57:18300 const base::android::JavaParamRef<jobject>& java_impl) {
Scott Violetbf8b8aa72020-01-28 19:37:32301 Browser::PersistenceInfo persistence_info;
302 Browser::PersistenceInfo* persistence_info_ptr = nullptr;
303
304 if (j_persistence_id.obj()) {
305 const std::string persistence_id =
306 base::android::ConvertJavaStringToUTF8(j_persistence_id);
307 if (!persistence_id.empty()) {
308 persistence_info.id = persistence_id;
309 if (j_persistence_crypto_key.obj()) {
310 base::android::JavaByteArrayToByteVector(
311 env, j_persistence_crypto_key, &(persistence_info.last_crypto_key));
312 }
313 persistence_info_ptr = &persistence_info;
314 }
315 }
316 return reinterpret_cast<intptr_t>(
317 new BrowserImpl(reinterpret_cast<ProfileImpl*>(profile),
318 persistence_info_ptr, java_impl));
Scott Violet009c09c2020-01-18 00:57:18319}
320
321static void JNI_BrowserImpl_DeleteBrowser(JNIEnv* env, jlong browser) {
322 delete reinterpret_cast<BrowserImpl*>(browser);
323}
324#endif
325
326} // namespace weblayer