1 // Copyright 2020 The Chromium Embedded Framework 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 "libcef/browser/chrome/chrome_browser_context.h"
6
7 #include "libcef/browser/thread_util.h"
8
9 #include "base/threading/thread_restrictions.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
12 #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
13 #include "chrome/browser/profiles/off_the_record_profile_impl.h"
14
ChromeBrowserContext(const CefRequestContextSettings & settings)15 ChromeBrowserContext::ChromeBrowserContext(
16 const CefRequestContextSettings& settings)
17 : CefBrowserContext(settings), weak_ptr_factory_(this) {}
18
19 ChromeBrowserContext::~ChromeBrowserContext() = default;
20
AsBrowserContext()21 content::BrowserContext* ChromeBrowserContext::AsBrowserContext() {
22 CHECK(!destroyed_);
23 return profile_;
24 }
25
AsProfile()26 Profile* ChromeBrowserContext::AsProfile() {
27 CHECK(!destroyed_);
28 return profile_;
29 }
30
IsInitialized() const31 bool ChromeBrowserContext::IsInitialized() const {
32 CEF_REQUIRE_UIT();
33 CHECK(!destroyed_);
34 return !!profile_;
35 }
36
StoreOrTriggerInitCallback(base::OnceClosure callback)37 void ChromeBrowserContext::StoreOrTriggerInitCallback(
38 base::OnceClosure callback) {
39 CEF_REQUIRE_UIT();
40 if (IsInitialized()) {
41 std::move(callback).Run();
42 } else {
43 init_callbacks_.emplace_back(std::move(callback));
44 }
45 }
46
InitializeAsync(base::OnceClosure initialized_cb)47 void ChromeBrowserContext::InitializeAsync(base::OnceClosure initialized_cb) {
48 init_callbacks_.emplace_back(std::move(initialized_cb));
49
50 CefBrowserContext::Initialize();
51
52 if (!cache_path_.empty()) {
53 auto* profile_manager = g_browser_process->profile_manager();
54 const auto& user_data_dir = profile_manager->user_data_dir();
55
56 if (cache_path_ == user_data_dir) {
57 // Use the default disk-based profile.
58 auto profile = profile_manager->GetPrimaryUserProfile();
59 ProfileCreated(profile, Profile::CreateStatus::CREATE_STATUS_INITIALIZED);
60 return;
61 } else if (cache_path_.DirName() == user_data_dir) {
62 // Create or load a specific disk-based profile. May continue
63 // synchronously or asynchronously.
64 profile_manager->CreateProfileAsync(
65 cache_path_,
66 base::BindRepeating(&ChromeBrowserContext::ProfileCreated,
67 weak_ptr_factory_.GetWeakPtr()));
68 return;
69 } else {
70 // All profile directories must be relative to |user_data_dir|.
71 LOG(ERROR) << "Cannot create profile at path "
72 << cache_path_.AsUTF8Unsafe();
73 }
74 }
75
76 // Default to creating a new/unique OffTheRecord profile.
77 ProfileCreated(nullptr, Profile::CreateStatus::CREATE_STATUS_LOCAL_FAIL);
78 }
79
Shutdown()80 void ChromeBrowserContext::Shutdown() {
81 CefBrowserContext::Shutdown();
82
83 // Allow potential deletion of the Profile at some future point (controlled
84 // by ProfileManager).
85 profile_keep_alive_.reset();
86
87 // |g_browser_process| may be nullptr during shutdown.
88 if (g_browser_process) {
89 if (should_destroy_) {
90 g_browser_process->profile_manager()
91 ->GetPrimaryUserProfile()
92 ->DestroyOffTheRecordProfile(profile_);
93 } else if (profile_) {
94 OnProfileWillBeDestroyed(profile_);
95 }
96 }
97 }
98
ProfileCreated(Profile * profile,Profile::CreateStatus status)99 void ChromeBrowserContext::ProfileCreated(Profile* profile,
100 Profile::CreateStatus status) {
101 Profile* parent_profile = nullptr;
102 OffTheRecordProfileImpl* otr_profile = nullptr;
103
104 if (status != Profile::CreateStatus::CREATE_STATUS_CREATED &&
105 status != Profile::CreateStatus::CREATE_STATUS_INITIALIZED) {
106 CHECK(!profile);
107 CHECK(!profile_);
108
109 // Profile creation may access the filesystem.
110 base::ScopedAllowBlockingForTesting allow_blocking;
111
112 // Creation of a disk-based profile failed for some reason. Create a
113 // new/unique OffTheRecord profile instead.
114 const auto& profile_id = Profile::OTRProfileID::CreateUniqueForCEF();
115 parent_profile =
116 g_browser_process->profile_manager()->GetPrimaryUserProfile();
117 profile_ = parent_profile->GetOffTheRecordProfile(
118 profile_id, /*create_if_needed=*/true);
119 otr_profile = static_cast<OffTheRecordProfileImpl*>(profile_);
120 status = Profile::CreateStatus::CREATE_STATUS_INITIALIZED;
121 should_destroy_ = true;
122 } else if (profile && !profile_) {
123 // May be CREATE_STATUS_CREATED or CREATE_STATUS_INITIALIZED since
124 // *CREATED isn't always sent for a disk-based profile that already
125 // exists.
126 profile_ = profile;
127 profile_->AddObserver(this);
128 profile_keep_alive_.reset(new ScopedProfileKeepAlive(
129 profile_, ProfileKeepAliveOrigin::kAppWindow));
130 }
131
132 if (status == Profile::CreateStatus::CREATE_STATUS_INITIALIZED) {
133 CHECK(profile_);
134
135 // Must set |profile_| before Init() calls
136 // ChromeContentBrowserClientCef::ConfigureNetworkContextParams so that
137 // CefBrowserContext::FromBrowserContext can find us.
138 if (otr_profile) {
139 otr_profile->Init();
140 parent_profile->NotifyOffTheRecordProfileCreated(otr_profile);
141 }
142
143 if (!init_callbacks_.empty()) {
144 for (auto& callback : init_callbacks_) {
145 std::move(callback).Run();
146 }
147 init_callbacks_.clear();
148 }
149 }
150 }
151
OnProfileWillBeDestroyed(Profile * profile)152 void ChromeBrowserContext::OnProfileWillBeDestroyed(Profile* profile) {
153 CHECK_EQ(profile_, profile);
154 profile_->RemoveObserver(this);
155 profile_ = nullptr;
156 destroyed_ = true;
157 }
158