refactor: allocate api::Session on cpp heap (#48141)
This commit is contained in:
parent
0917ed5f6f
commit
3ccb1bc0a8
32 changed files with 632 additions and 293 deletions
|
@ -8,16 +8,17 @@ electron objects that extend gin::Wrappable and gets
|
|||
allocated on the cpp heap
|
||||
|
||||
diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h
|
||||
index a507d1d837ab3ec2b2d3ae7978d9d410ab2ec2d1..a547ecacad732f73512abbe5da81483208bb9e81 100644
|
||||
index a507d1d837ab3ec2b2d3ae7978d9d410ab2ec2d1..5a69c5c7c5ed0e834e09ff3a2d0f0126ba4ccf99 100644
|
||||
--- a/gin/public/wrappable_pointer_tags.h
|
||||
+++ b/gin/public/wrappable_pointer_tags.h
|
||||
@@ -72,7 +72,8 @@ enum WrappablePointerTag : uint16_t {
|
||||
@@ -72,7 +72,9 @@ enum WrappablePointerTag : uint16_t {
|
||||
kTextInputControllerBindings, // content::TextInputControllerBindings
|
||||
kWebAXObjectProxy, // content::WebAXObjectProxy
|
||||
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
|
||||
- kLastPointerTag = kWrappedExceptionHandler,
|
||||
+ kElectronApp, // electron::api::App
|
||||
+ kLastPointerTag = kElectronApp,
|
||||
+ kElectronSession, // electron::api::Session
|
||||
+ kLastPointerTag = kElectronSession,
|
||||
};
|
||||
|
||||
static_assert(kLastPointerTag <
|
||||
|
|
|
@ -8,6 +8,30 @@ Restores part of https://chromium-review.googlesource.com/c/chromium/src/+/67991
|
|||
Patch can be removed once cppgc migration is complete
|
||||
https://github.com/electron/electron/issues/47922
|
||||
|
||||
diff --git a/gin/function_template.h b/gin/function_template.h
|
||||
index 84ab9585240a49048774811718f7ebd6f988e485..f062163cdd81def12fae7e507d18a9133dd0804d 100644
|
||||
--- a/gin/function_template.h
|
||||
+++ b/gin/function_template.h
|
||||
@@ -77,6 +77,7 @@ class GIN_EXPORT CallbackHolderBase {
|
||||
CallbackHolderBase* holder);
|
||||
~DisposeObserver() override;
|
||||
void OnBeforeDispose(v8::Isolate* isolate) override;
|
||||
+ void OnBeforeMicrotasksRunnerDispose(v8::Isolate* isolate) override {}
|
||||
void OnDisposed() override;
|
||||
|
||||
private:
|
||||
diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc
|
||||
index bb1639d73070a99984b72eb61afd001dec5b08ff..b036f324309c46c53b74124da3ea830d39a973e3 100644
|
||||
--- a/gin/isolate_holder.cc
|
||||
+++ b/gin/isolate_holder.cc
|
||||
@@ -224,6 +224,7 @@ void IsolateHolder::WillCreateMicrotasksRunner() {
|
||||
|
||||
void IsolateHolder::WillDestroyMicrotasksRunner() {
|
||||
DCHECK(g_initialized_microtasks_runner);
|
||||
+ isolate_data_->NotifyBeforeMicrotasksRunnerDispose();
|
||||
g_destroyed_microtasks_runner = true;
|
||||
}
|
||||
|
||||
diff --git a/gin/object_template_builder.cc b/gin/object_template_builder.cc
|
||||
index 5a31687bbd0fca61db3a7c41ed73d938340d6446..b84f5fd336bc4b61b2cd0b2fc92382b00e928701 100644
|
||||
--- a/gin/object_template_builder.cc
|
||||
|
@ -22,10 +46,10 @@ index 5a31687bbd0fca61db3a7c41ed73d938340d6446..b84f5fd336bc4b61b2cd0b2fc92382b0
|
|||
|
||||
ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate,
|
||||
diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc
|
||||
index 884990426f13a6abca22a60dd8cc0685f8435b23..64ac0a64a05105532f3cda898aeac68c21338e60 100644
|
||||
index 884990426f13a6abca22a60dd8cc0685f8435b23..d1014af4b63da244820ff865a8e824ddf68433a9 100644
|
||||
--- a/gin/per_isolate_data.cc
|
||||
+++ b/gin/per_isolate_data.cc
|
||||
@@ -68,12 +68,32 @@ PerIsolateData* PerIsolateData::From(Isolate* isolate) {
|
||||
@@ -68,12 +68,37 @@ PerIsolateData* PerIsolateData::From(Isolate* isolate) {
|
||||
return static_cast<PerIsolateData*>(isolate->GetData(kEmbedderNativeGin));
|
||||
}
|
||||
|
||||
|
@ -40,8 +64,13 @@ index 884990426f13a6abca22a60dd8cc0685f8435b23..64ac0a64a05105532f3cda898aeac68c
|
|||
object_templates_[info] = Eternal<ObjectTemplate>(isolate_, templ);
|
||||
}
|
||||
|
||||
+void PerIsolateData::SetFunctionTemplate(DeprecatedWrapperInfo* info,
|
||||
+ Local<FunctionTemplate> templ) {
|
||||
+void PerIsolateData::DeprecatedSetFunctionTemplate(
|
||||
+ DeprecatedWrapperInfo* info, Local<FunctionTemplate> templ) {
|
||||
+ deprecated_function_templates_[info] = Eternal<FunctionTemplate>(isolate_, templ);
|
||||
+}
|
||||
+
|
||||
+void PerIsolateData::SetFunctionTemplate(
|
||||
+ const WrapperInfo* info, Local<FunctionTemplate> templ) {
|
||||
+ function_templates_[info] = Eternal<FunctionTemplate>(isolate_, templ);
|
||||
+}
|
||||
+
|
||||
|
@ -58,12 +87,22 @@ index 884990426f13a6abca22a60dd8cc0685f8435b23..64ac0a64a05105532f3cda898aeac68c
|
|||
v8::Local<v8::ObjectTemplate> PerIsolateData::GetObjectTemplate(
|
||||
const WrapperInfo* info) {
|
||||
ObjectTemplateMap::iterator it = object_templates_.find(info);
|
||||
@@ -83,6 +103,15 @@ v8::Local<v8::ObjectTemplate> PerIsolateData::GetObjectTemplate(
|
||||
@@ -83,6 +108,25 @@ v8::Local<v8::ObjectTemplate> PerIsolateData::GetObjectTemplate(
|
||||
return it->second.Get(isolate_);
|
||||
}
|
||||
|
||||
+v8::Local<v8::FunctionTemplate> PerIsolateData::GetFunctionTemplate(
|
||||
+v8::Local<v8::FunctionTemplate> PerIsolateData::DeprecatedGetFunctionTemplate(
|
||||
+ DeprecatedWrapperInfo* info) {
|
||||
+ DeprecatedFunctionTemplateMap::iterator it =
|
||||
+ deprecated_function_templates_.find(info);
|
||||
+ if (it == deprecated_function_templates_.end()) {
|
||||
+ return v8::Local<v8::FunctionTemplate>();
|
||||
+ }
|
||||
+ return it->second.Get(isolate_);
|
||||
+}
|
||||
+
|
||||
+v8::Local<v8::FunctionTemplate> PerIsolateData::GetFunctionTemplate(
|
||||
+ const WrapperInfo* info) {
|
||||
+ FunctionTemplateMap::iterator it = function_templates_.find(info);
|
||||
+ if (it == function_templates_.end()) {
|
||||
+ return v8::Local<v8::FunctionTemplate>();
|
||||
|
@ -74,11 +113,35 @@ index 884990426f13a6abca22a60dd8cc0685f8435b23..64ac0a64a05105532f3cda898aeac68c
|
|||
void PerIsolateData::AddDisposeObserver(DisposeObserver* observer) {
|
||||
dispose_observers_.AddObserver(observer);
|
||||
}
|
||||
@@ -97,6 +141,12 @@ void PerIsolateData::NotifyBeforeDispose() {
|
||||
}
|
||||
}
|
||||
|
||||
+void PerIsolateData::NotifyBeforeMicrotasksRunnerDispose() {
|
||||
+ for (auto& observer : dispose_observers_) {
|
||||
+ observer.OnBeforeMicrotasksRunnerDispose(isolate_.get());
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void PerIsolateData::NotifyDisposed() {
|
||||
for (auto& observer : dispose_observers_) {
|
||||
observer.OnDisposed();
|
||||
diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h
|
||||
index bce889749415da341e6e6e4082ac06bbeb4bb80a..d748c1cf8cef7da90686686f1b8072bcd530541d 100644
|
||||
index bce889749415da341e6e6e4082ac06bbeb4bb80a..2f8abc344c77713fb10d83e51ba486c84ab93474 100644
|
||||
--- a/gin/per_isolate_data.h
|
||||
+++ b/gin/per_isolate_data.h
|
||||
@@ -51,11 +51,24 @@ class GIN_EXPORT PerIsolateData {
|
||||
@@ -34,6 +34,10 @@ class GIN_EXPORT PerIsolateData {
|
||||
// be entered before the observer is notified, but there will not be a
|
||||
// handle scope by default.
|
||||
virtual void OnBeforeDispose(v8::Isolate* isolate) = 0;
|
||||
+
|
||||
+ // Called just before the microtasks runner is about to be disposed.
|
||||
+ virtual void OnBeforeMicrotasksRunnerDispose(v8::Isolate* isolate) = 0;
|
||||
+
|
||||
// Called just after the isolate has been disposed.
|
||||
virtual void OnDisposed() = 0;
|
||||
};
|
||||
@@ -51,14 +55,36 @@ class GIN_EXPORT PerIsolateData {
|
||||
|
||||
static PerIsolateData* From(v8::Isolate* isolate);
|
||||
|
||||
|
@ -89,7 +152,12 @@ index bce889749415da341e6e6e4082ac06bbeb4bb80a..d748c1cf8cef7da90686686f1b8072bc
|
|||
void SetObjectTemplate(const WrapperInfo* info,
|
||||
v8::Local<v8::ObjectTemplate> object_template);
|
||||
|
||||
+ void SetFunctionTemplate(DeprecatedWrapperInfo* info,
|
||||
+ void DeprecatedSetFunctionTemplate(
|
||||
+ DeprecatedWrapperInfo* info,
|
||||
+ v8::Local<v8::FunctionTemplate> function_template);
|
||||
+
|
||||
+ void SetFunctionTemplate(
|
||||
+ const WrapperInfo* info,
|
||||
+ v8::Local<v8::FunctionTemplate> function_template);
|
||||
+
|
||||
+ v8::Local<v8::ObjectTemplate> DeprecatedGetObjectTemplate(
|
||||
|
@ -97,13 +165,20 @@ index bce889749415da341e6e6e4082ac06bbeb4bb80a..d748c1cf8cef7da90686686f1b8072bc
|
|||
+
|
||||
v8::Local<v8::ObjectTemplate> GetObjectTemplate(const WrapperInfo* info);
|
||||
|
||||
+ v8::Local<v8::FunctionTemplate> GetFunctionTemplate(
|
||||
+ v8::Local<v8::FunctionTemplate> DeprecatedGetFunctionTemplate(
|
||||
+ DeprecatedWrapperInfo* info);
|
||||
+
|
||||
+ v8::Local<v8::FunctionTemplate> GetFunctionTemplate(
|
||||
+ const WrapperInfo* info);
|
||||
+
|
||||
void AddDisposeObserver(DisposeObserver* observer);
|
||||
void RemoveDisposeObserver(DisposeObserver* observer);
|
||||
void NotifyBeforeDispose();
|
||||
@@ -74,14 +87,20 @@ class GIN_EXPORT PerIsolateData {
|
||||
+ void NotifyBeforeMicrotasksRunnerDispose();
|
||||
void NotifyDisposed();
|
||||
|
||||
void EnableIdleTasks(std::unique_ptr<V8IdleTaskRunner> idle_task_runner);
|
||||
@@ -74,14 +100,23 @@ class GIN_EXPORT PerIsolateData {
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -112,6 +187,8 @@ index bce889749415da341e6e6e4082ac06bbeb4bb80a..d748c1cf8cef7da90686686f1b8072bc
|
|||
typedef std::map<const WrapperInfo*, v8::Eternal<v8::ObjectTemplate>>
|
||||
ObjectTemplateMap;
|
||||
+ typedef std::map<DeprecatedWrapperInfo*, v8::Eternal<v8::FunctionTemplate>>
|
||||
+ DeprecatedFunctionTemplateMap;
|
||||
+ typedef std::map<const WrapperInfo*, v8::Eternal<v8::FunctionTemplate>>
|
||||
+ FunctionTemplateMap;
|
||||
|
||||
// PerIsolateData doesn't actually own |isolate_|. Instead, the isolate is
|
||||
|
@ -120,6 +197,7 @@ index bce889749415da341e6e6e4082ac06bbeb4bb80a..d748c1cf8cef7da90686686f1b8072bc
|
|||
raw_ptr<v8::ArrayBuffer::Allocator, DanglingUntriaged> allocator_;
|
||||
+ DeprecatedObjectTemplateMap deprecated_object_templates_;
|
||||
ObjectTemplateMap object_templates_;
|
||||
+ DeprecatedFunctionTemplateMap deprecated_function_templates_;
|
||||
+ FunctionTemplateMap function_templates_;
|
||||
base::ObserverList<DisposeObserver> dispose_observers_;
|
||||
std::shared_ptr<V8ForegroundTaskRunnerBase> task_runner_;
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "url/origin.h"
|
||||
#include "v8/include/v8-traced-handle.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "shell/browser/api/electron_api_extensions.h"
|
||||
|
@ -544,23 +545,27 @@ class DictionaryObserver final : public SpellcheckCustomDictionary::Observer {
|
|||
#endif // BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
|
||||
struct UserDataLink : base::SupportsUserData::Data {
|
||||
explicit UserDataLink(base::WeakPtr<Session> session_in)
|
||||
: session{std::move(session_in)} {}
|
||||
explicit UserDataLink(
|
||||
cppgc::WeakPersistent<gin::WeakCell<Session>> session_in)
|
||||
: session{session_in} {}
|
||||
|
||||
base::WeakPtr<Session> session;
|
||||
cppgc::WeakPersistent<gin::WeakCell<Session>> session;
|
||||
};
|
||||
|
||||
const void* kElectronApiSessionKey = &kElectronApiSessionKey;
|
||||
|
||||
} // namespace
|
||||
|
||||
gin::DeprecatedWrapperInfo Session::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
gin::WrapperInfo Session::kWrapperInfo = {{gin::kEmbedderNativeGin},
|
||||
gin::kElectronSession};
|
||||
|
||||
Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
||||
: isolate_(isolate),
|
||||
network_emulation_token_(base::UnguessableToken::Create()),
|
||||
browser_context_{
|
||||
raw_ref<ElectronBrowserContext>::from_ptr(browser_context)} {
|
||||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
data->AddDisposeObserver(this);
|
||||
// Observe DownloadManager to get download notifications.
|
||||
browser_context->GetDownloadManager()->AddObserver(this);
|
||||
|
||||
|
@ -572,7 +577,10 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
|||
|
||||
browser_context->SetUserData(
|
||||
kElectronApiSessionKey,
|
||||
std::make_unique<UserDataLink>(weak_factory_.GetWeakPtr()));
|
||||
std::make_unique<UserDataLink>(
|
||||
cppgc::WeakPersistent<gin::WeakCell<Session>>(
|
||||
weak_factory_.GetWeakCell(
|
||||
isolate->GetCppHeap()->GetAllocationHandle()))));
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
if (auto* service =
|
||||
|
@ -583,6 +591,11 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
|||
}
|
||||
|
||||
Session::~Session() {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
void Session::Dispose() {
|
||||
if (keep_alive_) {
|
||||
browser_context()->GetDownloadManager()->RemoveObserver(this);
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
|
@ -591,6 +604,7 @@ Session::~Session() {
|
|||
service->SetHunspellObserver(nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
|
@ -1307,7 +1321,7 @@ v8::Local<v8::Promise> Session::GetSharedDictionaryUsageInfo() {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
||||
if (cookies_.IsEmpty()) {
|
||||
if (cookies_.IsEmptyThreadSafe()) {
|
||||
auto handle = Cookies::Create(isolate, browser_context());
|
||||
cookies_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
|
@ -1316,7 +1330,7 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
|||
|
||||
v8::Local<v8::Value> Session::Extensions(v8::Isolate* isolate) {
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (extensions_.IsEmpty()) {
|
||||
if (extensions_.IsEmptyThreadSafe()) {
|
||||
v8::Local<v8::Value> handle;
|
||||
handle = Extensions::Create(isolate, browser_context()).ToV8();
|
||||
extensions_.Reset(isolate, handle);
|
||||
|
@ -1330,7 +1344,7 @@ v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
|
||||
if (service_worker_context_.IsEmpty()) {
|
||||
if (service_worker_context_.IsEmptyThreadSafe()) {
|
||||
v8::Local<v8::Value> handle;
|
||||
handle = ServiceWorkerContext::Create(isolate, browser_context()).ToV8();
|
||||
service_worker_context_.Reset(isolate, handle);
|
||||
|
@ -1339,7 +1353,7 @@ v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
||||
if (web_request_.IsEmpty()) {
|
||||
if (web_request_.IsEmptyThreadSafe()) {
|
||||
auto handle = WebRequest::Create(isolate, browser_context());
|
||||
web_request_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
|
@ -1347,7 +1361,7 @@ v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> Session::NetLog(v8::Isolate* isolate) {
|
||||
if (net_log_.IsEmpty()) {
|
||||
if (net_log_.IsEmptyThreadSafe()) {
|
||||
auto handle = NetLog::Create(isolate, browser_context());
|
||||
net_log_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
|
@ -1656,40 +1670,47 @@ bool Session::IsSpellCheckerEnabled() const {
|
|||
#endif // BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
|
||||
// static
|
||||
Session* Session::FromBrowserContext(content::BrowserContext* context) {
|
||||
gin::WeakCell<Session>* Session::FromBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
auto* data =
|
||||
static_cast<UserDataLink*>(context->GetUserData(kElectronApiSessionKey));
|
||||
return data ? data->session.get() : nullptr;
|
||||
if (data && data->session)
|
||||
return data->session.Get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Session> Session::CreateFrom(
|
||||
v8::Isolate* isolate,
|
||||
Session* Session::CreateFrom(v8::Isolate* isolate,
|
||||
ElectronBrowserContext* browser_context) {
|
||||
Session* existing = FromBrowserContext(browser_context);
|
||||
if (existing)
|
||||
return gin_helper::CreateHandle(isolate, existing);
|
||||
|
||||
auto handle =
|
||||
gin_helper::CreateHandle(isolate, new Session(isolate, browser_context));
|
||||
|
||||
// The Sessions should never be garbage collected, since the common pattern is
|
||||
// to use partition strings, instead of using the Session object directly.
|
||||
handle->Pin(isolate);
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
gin_helper::CallMethod(isolate, handle.get(), "_init");
|
||||
if (try_catch.HasCaught()) {
|
||||
node::errors::TriggerUncaughtException(isolate, try_catch);
|
||||
gin::WeakCell<Session>* existing = FromBrowserContext(browser_context);
|
||||
if (existing && existing->Get()) {
|
||||
return existing->Get();
|
||||
}
|
||||
|
||||
App::Get()->EmitWithoutEvent("session-created", handle);
|
||||
auto* session = cppgc::MakeGarbageCollected<Session>(
|
||||
isolate->GetCppHeap()->GetAllocationHandle(), isolate, browser_context);
|
||||
|
||||
return handle;
|
||||
v8::TryCatch try_catch(isolate);
|
||||
gin_helper::CallMethod(isolate, session, "_init");
|
||||
if (try_catch.HasCaught()) {
|
||||
node::errors::TriggerUncaughtException(isolate, try_catch);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session->GetWrapper(isolate).ToLocal(&wrapper)) {
|
||||
return nullptr;
|
||||
}
|
||||
App::Get()->EmitWithoutEvent("session-created", wrapper);
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
|
||||
Session* Session::FromPartition(v8::Isolate* isolate,
|
||||
const std::string& partition,
|
||||
base::Value::Dict options) {
|
||||
ElectronBrowserContext* browser_context;
|
||||
|
@ -1708,34 +1729,30 @@ gin_helper::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
|
|||
}
|
||||
|
||||
// static
|
||||
std::optional<gin_helper::Handle<Session>> Session::FromPath(
|
||||
v8::Isolate* isolate,
|
||||
Session* Session::FromPath(gin::Arguments* args,
|
||||
const base::FilePath& path,
|
||||
base::Value::Dict options) {
|
||||
ElectronBrowserContext* browser_context;
|
||||
|
||||
if (path.empty()) {
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
promise.RejectWithErrorMessage("An empty path was specified");
|
||||
return std::nullopt;
|
||||
args->ThrowTypeError("An empty path was specified");
|
||||
return nullptr;
|
||||
}
|
||||
if (!path.IsAbsolute()) {
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
promise.RejectWithErrorMessage("An absolute path was not provided");
|
||||
return std::nullopt;
|
||||
args->ThrowTypeError("An absolute path was not provided");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
browser_context =
|
||||
ElectronBrowserContext::FromPath(std::move(path), std::move(options));
|
||||
|
||||
return CreateFrom(isolate, browser_context);
|
||||
return CreateFrom(args->isolate(), browser_context);
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Session> Session::New() {
|
||||
void Session::New() {
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowError("Session objects cannot be created with 'new'");
|
||||
return {};
|
||||
}
|
||||
|
||||
void Session::FillObjectTemplate(v8::Isolate* isolate,
|
||||
|
@ -1821,12 +1838,31 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
|
|||
.Build();
|
||||
}
|
||||
|
||||
const char* Session::GetTypeName() {
|
||||
return GetClassName();
|
||||
void Session::Trace(cppgc::Visitor* visitor) const {
|
||||
gin::Wrappable<Session>::Trace(visitor);
|
||||
visitor->Trace(cookies_);
|
||||
visitor->Trace(extensions_);
|
||||
visitor->Trace(protocol_);
|
||||
visitor->Trace(net_log_);
|
||||
visitor->Trace(service_worker_context_);
|
||||
visitor->Trace(web_request_);
|
||||
visitor->Trace(weak_factory_);
|
||||
}
|
||||
|
||||
void Session::WillBeDestroyed() {
|
||||
ClearWeak();
|
||||
const gin::WrapperInfo* Session::wrapper_info() const {
|
||||
return &kWrapperInfo;
|
||||
}
|
||||
|
||||
const char* Session::GetHumanReadableName() const {
|
||||
return "Electron / Session";
|
||||
}
|
||||
|
||||
void Session::OnBeforeMicrotasksRunnerDispose(v8::Isolate* isolate) {
|
||||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
data->RemoveDisposeObserver(this);
|
||||
Dispose();
|
||||
weak_factory_.Invalidate();
|
||||
keep_alive_.Clear();
|
||||
}
|
||||
|
||||
} // namespace electron::api
|
||||
|
@ -1843,8 +1879,19 @@ v8::Local<v8::Value> FromPartition(const std::string& partition,
|
|||
}
|
||||
base::Value::Dict options;
|
||||
args->GetNext(&options);
|
||||
return Session::FromPartition(args->isolate(), partition, std::move(options))
|
||||
.ToV8();
|
||||
Session* session =
|
||||
Session::FromPartition(args->isolate(), partition, std::move(options));
|
||||
|
||||
if (session) {
|
||||
v8::HandleScope handle_scope(args->isolate());
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session->GetWrapper(args->isolate()).ToLocal(&wrapper)) {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
return wrapper;
|
||||
} else {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> FromPath(const base::FilePath& path,
|
||||
|
@ -1855,13 +1902,18 @@ v8::Local<v8::Value> FromPath(const base::FilePath& path,
|
|||
}
|
||||
base::Value::Dict options;
|
||||
args->GetNext(&options);
|
||||
std::optional<gin_helper::Handle<Session>> session_handle =
|
||||
Session::FromPath(args->isolate(), path, std::move(options));
|
||||
Session* session = Session::FromPath(args, path, std::move(options));
|
||||
|
||||
if (session_handle)
|
||||
return session_handle.value().ToV8();
|
||||
else
|
||||
if (session) {
|
||||
v8::HandleScope handle_scope(args->isolate());
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session->GetWrapper(args->isolate()).ToLocal(&wrapper)) {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
return wrapper;
|
||||
} else {
|
||||
return v8::Null(args->isolate());
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
|
@ -1870,7 +1922,8 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
void* priv) {
|
||||
v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set("Session", Session::GetConstructor(isolate, context));
|
||||
dict.Set("Session",
|
||||
Session::GetConstructor(isolate, context, &Session::kWrapperInfo));
|
||||
dict.SetMethod("fromPartition", &FromPartition);
|
||||
dict.SetMethod("fromPath", &FromPath);
|
||||
}
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
#include "base/values.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "gin/weak_cell.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "services/network/public/mojom/host_resolver.mojom-forward.h"
|
||||
#include "services/network/public/mojom/ssl_config.mojom-forward.h"
|
||||
#include "shell/browser/api/ipc_dispatcher.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
#include "shell/browser/net/resolve_proxy_helper.h"
|
||||
#include "shell/common/gin_helper/cleaned_up_at_exit.h"
|
||||
#include "shell/common/gin_helper/constructible.h"
|
||||
#include "shell/common/gin_helper/pinnable.h"
|
||||
#include "shell/common/gin_helper/wrappable.h"
|
||||
#include "shell/common/gin_helper/self_keep_alive.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
#include "chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h" // nogncheck
|
||||
|
@ -39,11 +39,6 @@ namespace gin {
|
|||
class Arguments;
|
||||
} // namespace gin
|
||||
|
||||
namespace gin_helper {
|
||||
template <typename T>
|
||||
class Handle;
|
||||
} // namespace gin_helper
|
||||
|
||||
namespace gin_helper {
|
||||
class Dictionary;
|
||||
class ErrorThrower;
|
||||
|
@ -53,6 +48,11 @@ namespace net {
|
|||
class ProxyConfig;
|
||||
}
|
||||
|
||||
namespace v8 {
|
||||
template <typename T>
|
||||
class TracedReference;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronBrowserContext;
|
||||
|
@ -60,11 +60,10 @@ struct PreloadScript;
|
|||
|
||||
namespace api {
|
||||
|
||||
class Session final : public gin_helper::DeprecatedWrappable<Session>,
|
||||
public gin_helper::Pinnable<Session>,
|
||||
class Session final : public gin::Wrappable<Session>,
|
||||
public gin_helper::Constructible<Session>,
|
||||
public gin_helper::EventEmitterMixin<Session>,
|
||||
public gin_helper::CleanedUpAtExit,
|
||||
public gin::PerIsolateData::DisposeObserver,
|
||||
public IpcDispatcher<Session>,
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
private SpellcheckHunspellDictionary::Observer,
|
||||
|
@ -72,39 +71,46 @@ class Session final : public gin_helper::DeprecatedWrappable<Session>,
|
|||
private content::DownloadManager::Observer {
|
||||
public:
|
||||
// Gets or creates Session from the |browser_context|.
|
||||
static gin_helper::Handle<Session> CreateFrom(
|
||||
v8::Isolate* isolate,
|
||||
static Session* CreateFrom(v8::Isolate* isolate,
|
||||
ElectronBrowserContext* browser_context);
|
||||
static gin_helper::Handle<Session> New(); // Dummy, do not use!
|
||||
static void New(); // Dummy, do not use!
|
||||
|
||||
static Session* FromBrowserContext(content::BrowserContext* context);
|
||||
static gin::WeakCell<Session>* FromBrowserContext(
|
||||
content::BrowserContext* context);
|
||||
|
||||
// Gets the Session of |partition|.
|
||||
static gin_helper::Handle<Session> FromPartition(
|
||||
v8::Isolate* isolate,
|
||||
static Session* FromPartition(v8::Isolate* isolate,
|
||||
const std::string& partition,
|
||||
base::Value::Dict options = {});
|
||||
|
||||
// Gets the Session based on |path|.
|
||||
static std::optional<gin_helper::Handle<Session>> FromPath(
|
||||
v8::Isolate* isolate,
|
||||
static Session* FromPath(gin::Arguments* args,
|
||||
const base::FilePath& path,
|
||||
base::Value::Dict options = {});
|
||||
|
||||
static void FillObjectTemplate(v8::Isolate*, v8::Local<v8::ObjectTemplate>);
|
||||
static const char* GetClassName() { return "Session"; }
|
||||
|
||||
Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context);
|
||||
~Session() override;
|
||||
|
||||
ElectronBrowserContext* browser_context() const {
|
||||
return &browser_context_.get();
|
||||
}
|
||||
|
||||
// gin_helper::Wrappable
|
||||
static gin::DeprecatedWrapperInfo kWrapperInfo;
|
||||
static void FillObjectTemplate(v8::Isolate*, v8::Local<v8::ObjectTemplate>);
|
||||
static const char* GetClassName() { return "Session"; }
|
||||
const char* GetTypeName() override;
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
void Trace(cppgc::Visitor*) const override;
|
||||
const gin::WrapperInfo* wrapper_info() const override;
|
||||
const char* GetHumanReadableName() const override;
|
||||
|
||||
// gin_helper::CleanedUpAtExit
|
||||
void WillBeDestroyed() override;
|
||||
// gin::PerIsolateData::DisposeObserver
|
||||
void OnBeforeDispose(v8::Isolate* isolate) override {}
|
||||
void OnBeforeMicrotasksRunnerDispose(v8::Isolate* isolate) override;
|
||||
void OnDisposed() override {}
|
||||
|
||||
// Methods.
|
||||
void Dispose();
|
||||
v8::Local<v8::Promise> ResolveHost(
|
||||
std::string host,
|
||||
std::optional<network::mojom::ResolveHostParametersPtr> params);
|
||||
|
@ -180,9 +186,6 @@ class Session final : public gin_helper::DeprecatedWrappable<Session>,
|
|||
Session& operator=(const Session&) = delete;
|
||||
|
||||
protected:
|
||||
Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context);
|
||||
~Session() override;
|
||||
|
||||
// content::DownloadManager::Observer:
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
download::DownloadItem* item) override;
|
||||
|
@ -202,12 +205,12 @@ class Session final : public gin_helper::DeprecatedWrappable<Session>,
|
|||
v8::Local<v8::Value> val);
|
||||
|
||||
// Cached gin_helper::Wrappable objects.
|
||||
v8::Global<v8::Value> cookies_;
|
||||
v8::Global<v8::Value> extensions_;
|
||||
v8::Global<v8::Value> protocol_;
|
||||
v8::Global<v8::Value> net_log_;
|
||||
v8::Global<v8::Value> service_worker_context_;
|
||||
v8::Global<v8::Value> web_request_;
|
||||
v8::TracedReference<v8::Value> cookies_;
|
||||
v8::TracedReference<v8::Value> extensions_;
|
||||
v8::TracedReference<v8::Value> protocol_;
|
||||
v8::TracedReference<v8::Value> net_log_;
|
||||
v8::TracedReference<v8::Value> service_worker_context_;
|
||||
v8::TracedReference<v8::Value> web_request_;
|
||||
|
||||
raw_ptr<v8::Isolate> isolate_;
|
||||
|
||||
|
@ -216,7 +219,9 @@ class Session final : public gin_helper::DeprecatedWrappable<Session>,
|
|||
|
||||
const raw_ref<ElectronBrowserContext> browser_context_;
|
||||
|
||||
base::WeakPtrFactory<Session> weak_factory_{this};
|
||||
gin::WeakCellFactory<Session> weak_factory_{this};
|
||||
|
||||
gin_helper::SelfKeepAlive<Session> keep_alive_{this};
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -87,7 +87,6 @@
|
|||
#include "services/service_manager/public/cpp/interface_provider.h"
|
||||
#include "shell/browser/api/electron_api_browser_window.h"
|
||||
#include "shell/browser/api/electron_api_debugger.h"
|
||||
#include "shell/browser/api/electron_api_session.h"
|
||||
#include "shell/browser/api/electron_api_web_frame_main.h"
|
||||
#include "shell/browser/api/frame_subscriber.h"
|
||||
#include "shell/browser/api/message_port.h"
|
||||
|
@ -755,8 +754,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
script_executor_ = std::make_unique<extensions::ScriptExecutor>(web_contents);
|
||||
#endif
|
||||
|
||||
auto session = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
session_ = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
|
||||
SetUserAgent(GetBrowserContext()->GetUserAgent());
|
||||
|
||||
|
@ -778,9 +776,9 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
{
|
||||
DCHECK(type != Type::kRemote)
|
||||
<< "Can't take ownership of a remote WebContents";
|
||||
auto session = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
InitWithSessionAndOptions(isolate, std::move(web_contents), session,
|
||||
session_ = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
InitWithSessionAndOptions(isolate, std::move(web_contents),
|
||||
session_->browser_context(),
|
||||
gin::Dictionary::CreateEmpty(isolate));
|
||||
}
|
||||
|
||||
|
@ -829,15 +827,15 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
|
||||
// Obtain the session.
|
||||
std::string partition;
|
||||
gin_helper::Handle<api::Session> session;
|
||||
if (options.Get("session", &session) && !session.IsEmpty()) {
|
||||
api::Session* session = nullptr;
|
||||
if (options.Get("session", &session) && session) {
|
||||
} else if (options.Get("partition", &partition)) {
|
||||
session = Session::FromPartition(isolate, partition);
|
||||
} else {
|
||||
// Use the default session if not specified.
|
||||
session = Session::FromPartition(isolate, "");
|
||||
}
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
session_ = session;
|
||||
|
||||
std::unique_ptr<content::WebContents> web_contents;
|
||||
if (is_guest()) {
|
||||
|
@ -886,7 +884,8 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
web_contents = content::WebContents::Create(params);
|
||||
}
|
||||
|
||||
InitWithSessionAndOptions(isolate, std::move(web_contents), session, options);
|
||||
InitWithSessionAndOptions(isolate, std::move(web_contents),
|
||||
session->browser_context(), options);
|
||||
}
|
||||
|
||||
void WebContents::InitZoomController(content::WebContents* web_contents,
|
||||
|
@ -907,10 +906,10 @@ void WebContents::InitZoomController(content::WebContents* web_contents,
|
|||
void WebContents::InitWithSessionAndOptions(
|
||||
v8::Isolate* isolate,
|
||||
std::unique_ptr<content::WebContents> owned_web_contents,
|
||||
gin_helper::Handle<api::Session> session,
|
||||
ElectronBrowserContext* browser_context,
|
||||
const gin_helper::Dictionary& options) {
|
||||
Observe(owned_web_contents.get());
|
||||
InitWithWebContents(std::move(owned_web_contents), session->browser_context(),
|
||||
InitWithWebContents(std::move(owned_web_contents), browser_context,
|
||||
is_guest());
|
||||
|
||||
inspectable_web_contents_->GetView()->SetDelegate(this);
|
||||
|
@ -3754,7 +3753,12 @@ v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow(
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
|
||||
return v8::Local<v8::Value>::New(isolate, session_);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!session_->GetWrapper(isolate).ToLocal(&wrapper)) {
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, wrapper);
|
||||
}
|
||||
|
||||
content::WebContents* WebContents::HostWebContents() const {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "content/public/common/stop_find_action.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "printing/buildflags/buildflags.h"
|
||||
#include "shell/browser/api/electron_api_session.h"
|
||||
#include "shell/browser/api/save_page_handler.h"
|
||||
#include "shell/browser/background_throttling_source.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include "shell/common/gin_helper/wrappable.h"
|
||||
#include "shell/common/web_contents_utility.mojom.h"
|
||||
#include "ui/base/models/image_model.h"
|
||||
#include "v8/include/cppgc/persistent.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "extensions/common/mojom/view_type.mojom-forward.h"
|
||||
|
@ -479,7 +481,7 @@ class WebContents final : public ExclusiveAccessContext,
|
|||
void InitWithSessionAndOptions(
|
||||
v8::Isolate* isolate,
|
||||
std::unique_ptr<content::WebContents> web_contents,
|
||||
gin_helper::Handle<class Session> session,
|
||||
ElectronBrowserContext* browser_context,
|
||||
const gin_helper::Dictionary& options);
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
|
@ -768,7 +770,7 @@ class WebContents final : public ExclusiveAccessContext,
|
|||
// Update the html fullscreen flag in both browser and renderer.
|
||||
void UpdateHtmlApiFullscreen(bool fullscreen);
|
||||
|
||||
v8::Global<v8::Value> session_;
|
||||
cppgc::Persistent<api::Session> session_;
|
||||
v8::Global<v8::Value> devtools_web_contents_;
|
||||
v8::Global<v8::Value> debugger_;
|
||||
|
||||
|
|
|
@ -44,68 +44,80 @@ void ElectronApiIPCHandlerImpl::OnConnectionError() {
|
|||
void ElectronApiIPCHandlerImpl::Message(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, internal);
|
||||
auto event = MakeIPCEvent(isolate, session->Get(), internal);
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->Message(event, channel, std::move(arguments));
|
||||
session->Get()->Message(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
void ElectronApiIPCHandlerImpl::Invoke(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
InvokeCallback callback) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, internal, std::move(callback));
|
||||
auto event =
|
||||
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->Invoke(event, channel, std::move(arguments));
|
||||
session->Get()->Invoke(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiIPCHandlerImpl::ReceivePostMessage(
|
||||
const std::string& channel,
|
||||
blink::TransferableMessage message) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, false);
|
||||
auto event = MakeIPCEvent(isolate, session->Get(), false);
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->ReceivePostMessage(event, channel, std::move(message));
|
||||
session->Get()->ReceivePostMessage(event, channel, std::move(message));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiIPCHandlerImpl::MessageSync(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
MessageSyncCallback callback) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, internal, std::move(callback));
|
||||
auto event =
|
||||
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->MessageSync(event, channel, std::move(arguments));
|
||||
session->Get()->MessageSync(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiIPCHandlerImpl::MessageHost(const std::string& channel,
|
||||
blink::CloneableMessage arguments) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, false);
|
||||
auto event = MakeIPCEvent(isolate, session->Get(), false);
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->MessageHost(event, channel, std::move(arguments));
|
||||
session->Get()->MessageHost(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
content::RenderFrameHost* ElectronApiIPCHandlerImpl::GetRenderFrameHost() {
|
||||
return content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||
}
|
||||
|
||||
api::Session* ElectronApiIPCHandlerImpl::GetSession() {
|
||||
gin::WeakCell<api::Session>* ElectronApiIPCHandlerImpl::GetSession() {
|
||||
auto* rfh = GetRenderFrameHost();
|
||||
return rfh ? api::Session::FromBrowserContext(rfh->GetBrowserContext())
|
||||
: nullptr;
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace content {
|
|||
class RenderFrameHost;
|
||||
}
|
||||
|
||||
namespace gin {
|
||||
template <typename T>
|
||||
class WeakCell;
|
||||
} // namespace gin
|
||||
|
||||
namespace electron {
|
||||
class ElectronApiIPCHandlerImpl : public mojom::ElectronApiIPC,
|
||||
private content::WebContentsObserver {
|
||||
|
@ -65,7 +70,7 @@ class ElectronApiIPCHandlerImpl : public mojom::ElectronApiIPC,
|
|||
void OnConnectionError();
|
||||
|
||||
content::RenderFrameHost* GetRenderFrameHost();
|
||||
api::Session* GetSession();
|
||||
gin::WeakCell<api::Session>* GetSession();
|
||||
|
||||
gin_helper::Handle<gin_helper::internal::Event> MakeIPCEvent(
|
||||
v8::Isolate* isolate,
|
||||
|
|
|
@ -71,51 +71,61 @@ void ElectronApiSWIPCHandlerImpl::RemoteDisconnected() {
|
|||
void ElectronApiSWIPCHandlerImpl::Message(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, internal);
|
||||
auto event = MakeIPCEvent(isolate, session->Get(), internal);
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->Message(event, channel, std::move(arguments));
|
||||
session->Get()->Message(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiSWIPCHandlerImpl::Invoke(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
InvokeCallback callback) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, internal, std::move(callback));
|
||||
auto event =
|
||||
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->Invoke(event, channel, std::move(arguments));
|
||||
session->Get()->Invoke(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiSWIPCHandlerImpl::ReceivePostMessage(
|
||||
const std::string& channel,
|
||||
blink::TransferableMessage message) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, false);
|
||||
auto event = MakeIPCEvent(isolate, session->Get(), false);
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->ReceivePostMessage(event, channel, std::move(message));
|
||||
session->Get()->ReceivePostMessage(event, channel, std::move(message));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiSWIPCHandlerImpl::MessageSync(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
MessageSyncCallback callback) {
|
||||
auto* session = GetSession();
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
auto event = MakeIPCEvent(isolate, session, internal, std::move(callback));
|
||||
auto event =
|
||||
MakeIPCEvent(isolate, session->Get(), internal, std::move(callback));
|
||||
if (event.IsEmpty())
|
||||
return;
|
||||
session->MessageSync(event, channel, std::move(arguments));
|
||||
session->Get()->MessageSync(event, channel, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiSWIPCHandlerImpl::MessageHost(
|
||||
|
@ -130,7 +140,7 @@ ElectronBrowserContext* ElectronApiSWIPCHandlerImpl::GetBrowserContext() {
|
|||
return browser_context;
|
||||
}
|
||||
|
||||
api::Session* ElectronApiSWIPCHandlerImpl::GetSession() {
|
||||
gin::WeakCell<api::Session>* ElectronApiSWIPCHandlerImpl::GetSession() {
|
||||
return api::Session::FromBrowserContext(GetBrowserContext());
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace content {
|
|||
class RenderProcessHost;
|
||||
}
|
||||
|
||||
namespace gin {
|
||||
template <typename T>
|
||||
class WeakCell;
|
||||
} // namespace gin
|
||||
|
||||
namespace electron {
|
||||
class ElectronBrowserContext;
|
||||
|
||||
|
@ -68,7 +73,7 @@ class ElectronApiSWIPCHandlerImpl : public mojom::ElectronApiIPC,
|
|||
|
||||
private:
|
||||
ElectronBrowserContext* GetBrowserContext();
|
||||
api::Session* GetSession();
|
||||
gin::WeakCell<api::Session>* GetSession();
|
||||
|
||||
gin_helper::Handle<gin_helper::internal::Event> MakeIPCEvent(
|
||||
v8::Isolate* isolate,
|
||||
|
|
|
@ -56,13 +56,13 @@ class EventEmitterMixin {
|
|||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
auto* wrapper_info = &(static_cast<T*>(this)->kWrapperInfo);
|
||||
v8::Local<v8::FunctionTemplate> constructor =
|
||||
data->GetFunctionTemplate(wrapper_info);
|
||||
data->DeprecatedGetFunctionTemplate(wrapper_info);
|
||||
if (constructor.IsEmpty()) {
|
||||
constructor = v8::FunctionTemplate::New(isolate);
|
||||
constructor->SetClassName(
|
||||
gin::StringToV8(isolate, static_cast<T*>(this)->GetTypeName()));
|
||||
constructor->Inherit(internal::GetEventEmitterTemplate(isolate));
|
||||
data->SetFunctionTemplate(wrapper_info, constructor);
|
||||
data->DeprecatedSetFunctionTemplate(wrapper_info, constructor);
|
||||
}
|
||||
return gin::ObjectTemplateBuilder(isolate,
|
||||
static_cast<T*>(this)->GetTypeName(),
|
||||
|
|
|
@ -732,8 +732,9 @@ void FileSystemAccessPermissionContext::DidCheckPathAgainstBlocklist(
|
|||
}
|
||||
|
||||
if (should_block) {
|
||||
auto* session =
|
||||
gin::WeakCell<api::Session>* session =
|
||||
electron::api::Session::FromBrowserContext(browser_context());
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Object> details =
|
||||
|
@ -742,11 +743,12 @@ void FileSystemAccessPermissionContext::DidCheckPathAgainstBlocklist(
|
|||
.Set("isDirectory", handle_type == HandleType::kDirectory)
|
||||
.Set("path", path_info.path)
|
||||
.Build();
|
||||
session->Emit(
|
||||
session->Get()->Emit(
|
||||
"file-system-access-restricted", details,
|
||||
base::BindRepeating(
|
||||
&FileSystemAccessPermissionContext::OnRestrictedPathResult,
|
||||
weak_factory_.GetWeakPtr(), path_info.path));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -293,14 +293,15 @@ void HidChooserContext::RevokeDevicePermission(
|
|||
} else {
|
||||
RevokeEphemeralDevicePermission(origin, device);
|
||||
}
|
||||
api::Session* session = api::Session::FromBrowserContext(browser_context_);
|
||||
if (session) {
|
||||
gin::WeakCell<api::Session>* session =
|
||||
api::Session::FromBrowserContext(browser_context_);
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto details = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
details.Set("device", device.Clone());
|
||||
details.Set("origin", origin.Serialize());
|
||||
session->Emit("hid-device-revoked", details);
|
||||
session->Get()->Emit("hid-device-revoked", details);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ const std::string& HidChooserController::PhysicalDeviceIdFromDeviceInfo(
|
|||
: device.physical_device_id;
|
||||
}
|
||||
|
||||
api::Session* HidChooserController::GetSession() {
|
||||
gin::WeakCell<api::Session>* HidChooserController::GetSession() {
|
||||
if (!web_contents()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -137,8 +137,8 @@ void HidChooserController::OnDeviceAdded(
|
|||
return;
|
||||
|
||||
if (AddDeviceInfo(device)) {
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
@ -146,7 +146,7 @@ void HidChooserController::OnDeviceAdded(
|
|||
.Set("device", device.Clone())
|
||||
.Set("frame", rfh)
|
||||
.Build();
|
||||
session->Emit("hid-device-added", details);
|
||||
session->Get()->Emit("hid-device-added", details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,8 +156,8 @@ void HidChooserController::OnDeviceRemoved(
|
|||
if (!base::Contains(items_, PhysicalDeviceIdFromDeviceInfo(device)))
|
||||
return;
|
||||
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
@ -165,7 +165,7 @@ void HidChooserController::OnDeviceRemoved(
|
|||
.Set("device", device.Clone())
|
||||
.Set("frame", rfh)
|
||||
.Build();
|
||||
session->Emit("hid-device-removed", details);
|
||||
session->Get()->Emit("hid-device-removed", details);
|
||||
}
|
||||
RemoveDeviceInfo(device);
|
||||
}
|
||||
|
@ -239,8 +239,8 @@ void HidChooserController::OnGotDevices(
|
|||
observation_.Observe(chooser_context_.get());
|
||||
|
||||
bool prevent_default = false;
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
@ -248,8 +248,8 @@ void HidChooserController::OnGotDevices(
|
|||
.Set("deviceList", devicesToDisplay)
|
||||
.Set("frame", rfh)
|
||||
.Build();
|
||||
prevent_default =
|
||||
session->Emit("select-hid-device", details,
|
||||
prevent_default = session->Get()->Emit(
|
||||
"select-hid-device", details,
|
||||
base::BindRepeating(&HidChooserController::OnDeviceChosen,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ class WebContents;
|
|||
|
||||
namespace gin {
|
||||
class Arguments;
|
||||
}
|
||||
template <typename T>
|
||||
class WeakCell;
|
||||
} // namespace gin
|
||||
|
||||
namespace electron {
|
||||
namespace api {
|
||||
|
@ -78,7 +80,7 @@ class HidChooserController
|
|||
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
|
||||
|
||||
private:
|
||||
api::Session* GetSession();
|
||||
gin::WeakCell<api::Session>* GetSession();
|
||||
void OnGotDevices(std::vector<device::mojom::HidDeviceInfoPtr> devices);
|
||||
bool DisplayDevice(const device::mojom::HidDeviceInfo& device) const;
|
||||
bool FilterMatchesAny(const device::mojom::HidDeviceInfo& device) const;
|
||||
|
|
|
@ -31,9 +31,10 @@ void NetworkHintsHandlerImpl::Preconnect(const url::SchemeHostPort& url,
|
|||
if (!browser_context_) {
|
||||
return;
|
||||
}
|
||||
auto* session = electron::api::Session::FromBrowserContext(browser_context_);
|
||||
if (session) {
|
||||
session->Emit("preconnect", url.GetURL(), allow_credentials);
|
||||
gin::WeakCell<electron::api::Session>* session =
|
||||
electron::api::Session::FromBrowserContext(browser_context_);
|
||||
if (session && session->Get()) {
|
||||
session->Get()->Emit("preconnect", url.GetURL(), allow_credentials);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -149,17 +149,16 @@ void SerialChooserContext::RevokePortPermissionWebInitiated(
|
|||
|
||||
auto* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||
api::Session* session =
|
||||
gin::WeakCell<api::Session>* session =
|
||||
api::Session::FromBrowserContext(web_contents->GetBrowserContext());
|
||||
|
||||
if (session) {
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto details = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
details.Set("port", it->second);
|
||||
details.SetGetter("frame", render_frame_host);
|
||||
details.Set("origin", origin.Serialize());
|
||||
session->Emit("serial-port-revoked", details);
|
||||
session->Get()->Emit("serial-port-revoked", details);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ SerialChooserController::~SerialChooserController() {
|
|||
RunCallback(/*port=*/nullptr);
|
||||
}
|
||||
|
||||
api::Session* SerialChooserController::GetSession() {
|
||||
gin::WeakCell<api::Session>* SerialChooserController::GetSession() {
|
||||
if (!web_contents_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -180,9 +180,10 @@ void SerialChooserController::OnPortAdded(
|
|||
|
||||
ports_.push_back(port.Clone());
|
||||
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
session->Emit("serial-port-added", port.Clone(), web_contents_.get());
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
session->Get()->Emit("serial-port-added", port.Clone(),
|
||||
web_contents_.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,8 +192,11 @@ void SerialChooserController::OnPortRemoved(
|
|||
const auto it = std::ranges::find(ports_, port.token,
|
||||
&device::mojom::SerialPortInfo::token);
|
||||
if (it != ports_.end()) {
|
||||
if (api::Session* session = GetSession())
|
||||
session->Emit("serial-port-removed", port.Clone(), web_contents_.get());
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
session->Get()->Emit("serial-port-removed", port.Clone(),
|
||||
web_contents_.get());
|
||||
}
|
||||
ports_.erase(it);
|
||||
}
|
||||
}
|
||||
|
@ -236,8 +240,9 @@ void SerialChooserController::OnGetDevices(
|
|||
}
|
||||
|
||||
bool prevent_default = false;
|
||||
if (api::Session* session = GetSession()) {
|
||||
prevent_default = session->Emit(
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
prevent_default = session->Get()->Emit(
|
||||
"select-serial-port", ports_, web_contents_.get(),
|
||||
base::BindRepeating(&SerialChooserController::OnDeviceChosen,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
|
|
|
@ -24,6 +24,11 @@ class RenderFrameHost;
|
|||
class WebContents;
|
||||
} // namespace content
|
||||
|
||||
namespace gin {
|
||||
template <typename T>
|
||||
class WeakCell;
|
||||
} // namespace gin
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
@ -64,7 +69,7 @@ class SerialChooserController final
|
|||
bool powered) override;
|
||||
|
||||
private:
|
||||
api::Session* GetSession();
|
||||
gin::WeakCell<api::Session>* GetSession();
|
||||
void GetDevices();
|
||||
void OnGetDevices(std::vector<device::mojom::SerialPortInfoPtr> ports);
|
||||
bool DisplayDevice(const device::mojom::SerialPortInfo& port) const;
|
||||
|
|
|
@ -276,14 +276,15 @@ void UsbChooserContext::RevokeObjectPermissionInternal(
|
|||
}
|
||||
}
|
||||
|
||||
api::Session* session = api::Session::FromBrowserContext(browser_context_);
|
||||
if (session) {
|
||||
gin::WeakCell<api::Session>* session =
|
||||
api::Session::FromBrowserContext(browser_context_);
|
||||
if (session && session->Get()) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto details = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
details.Set("device", object);
|
||||
details.Set("origin", origin.Serialize());
|
||||
session->Emit("usb-device-revoked", details);
|
||||
session->Get()->Emit("usb-device-revoked", details);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ UsbChooserController::~UsbChooserController() {
|
|||
RunCallback(/*device_info=*/nullptr);
|
||||
}
|
||||
|
||||
api::Session* UsbChooserController::GetSession() {
|
||||
gin::WeakCell<api::Session>* UsbChooserController::GetSession() {
|
||||
if (!web_contents()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -68,18 +68,20 @@ api::Session* UsbChooserController::GetSession() {
|
|||
void UsbChooserController::OnDeviceAdded(
|
||||
const device::mojom::UsbDeviceInfo& device_info) {
|
||||
if (DisplayDevice(device_info)) {
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
session->Emit("usb-device-added", device_info.Clone(), web_contents());
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
session->Get()->Emit("usb-device-added", device_info.Clone(),
|
||||
web_contents());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UsbChooserController::OnDeviceRemoved(
|
||||
const device::mojom::UsbDeviceInfo& device_info) {
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
session->Emit("usb-device-removed", device_info.Clone(), web_contents());
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
session->Get()->Emit("usb-device-removed", device_info.Clone(),
|
||||
web_contents());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,8 +116,8 @@ void UsbChooserController::GotUsbDeviceList(
|
|||
observation_.Observe(chooser_context_.get());
|
||||
|
||||
bool prevent_default = false;
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
gin::WeakCell<api::Session>* session = GetSession();
|
||||
if (session && session->Get()) {
|
||||
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope{isolate};
|
||||
|
@ -130,8 +132,8 @@ void UsbChooserController::GotUsbDeviceList(
|
|||
.Set("frame", rfh)
|
||||
.Build();
|
||||
|
||||
prevent_default =
|
||||
session->Emit("select-usb-device", details,
|
||||
prevent_default = session->Get()->Emit(
|
||||
"select-usb-device", details,
|
||||
base::BindRepeating(&UsbChooserController::OnDeviceChosen,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ class WebContents;
|
|||
|
||||
namespace gin {
|
||||
class Arguments;
|
||||
}
|
||||
template <typename T>
|
||||
class WeakCell;
|
||||
} // namespace gin
|
||||
|
||||
namespace electron {
|
||||
class ElectronUsbDelegate;
|
||||
|
@ -57,7 +59,7 @@ class UsbChooserController final : private UsbChooserContext::DeviceObserver,
|
|||
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
|
||||
|
||||
private:
|
||||
api::Session* GetSession();
|
||||
gin::WeakCell<api::Session>* GetSession();
|
||||
void GotUsbDeviceList(std::vector<device::mojom::UsbDeviceInfoPtr> devices);
|
||||
bool DisplayDevice(const device::mojom::UsbDeviceInfo& device) const;
|
||||
void RunCallback(device::mojom::UsbDeviceInfoPtr device_info);
|
||||
|
|
|
@ -577,11 +577,11 @@ gin::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
|
|||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
auto* wrapper_info = &kWrapperInfo;
|
||||
v8::Local<v8::FunctionTemplate> constructor =
|
||||
data->GetFunctionTemplate(wrapper_info);
|
||||
data->DeprecatedGetFunctionTemplate(wrapper_info);
|
||||
if (constructor.IsEmpty()) {
|
||||
constructor = v8::FunctionTemplate::New(isolate);
|
||||
constructor->SetClassName(gin::StringToV8(isolate, GetTypeName()));
|
||||
data->SetFunctionTemplate(wrapper_info, constructor);
|
||||
data->DeprecatedSetFunctionTemplate(wrapper_info, constructor);
|
||||
}
|
||||
return gin::ObjectTemplateBuilder(isolate, GetTypeName(),
|
||||
constructor->InstanceTemplate())
|
||||
|
|
|
@ -698,13 +698,14 @@ gin_helper::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
|
|||
ElectronBrowserContext* browser_context = nullptr;
|
||||
if (electron::IsBrowserProcess()) {
|
||||
std::string partition;
|
||||
gin_helper::Handle<Session> session;
|
||||
Session* session = nullptr;
|
||||
if (!opts.Get("session", &session)) {
|
||||
if (opts.Get("partition", &partition))
|
||||
session = Session::FromPartition(args->isolate(), partition);
|
||||
else // default session
|
||||
session = Session::FromPartition(args->isolate(), "");
|
||||
}
|
||||
if (session)
|
||||
browser_context = session->browser_context();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ class Constructible {
|
|||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
auto* wrapper_info = &T::kWrapperInfo;
|
||||
v8::Local<v8::FunctionTemplate> constructor =
|
||||
data->GetFunctionTemplate(wrapper_info);
|
||||
data->DeprecatedGetFunctionTemplate(wrapper_info);
|
||||
if (constructor.IsEmpty()) {
|
||||
constructor = gin::CreateConstructorFunctionTemplate(
|
||||
isolate, base::BindRepeating(&T::New));
|
||||
|
@ -59,6 +59,30 @@ class Constructible {
|
|||
T::FillObjectTemplate(isolate, constructor->PrototypeTemplate());
|
||||
data->DeprecatedSetObjectTemplate(wrapper_info,
|
||||
constructor->InstanceTemplate());
|
||||
data->DeprecatedSetFunctionTemplate(wrapper_info, constructor);
|
||||
}
|
||||
return constructor->GetFunction(context).ToLocalChecked();
|
||||
}
|
||||
|
||||
static v8::Local<v8::Function> GetConstructor(
|
||||
v8::Isolate* const isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
gin::WrapperInfo* wrapper_info) {
|
||||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
v8::Local<v8::FunctionTemplate> constructor =
|
||||
data->GetFunctionTemplate(wrapper_info);
|
||||
if (constructor.IsEmpty()) {
|
||||
constructor = gin::CreateConstructorFunctionTemplate(
|
||||
isolate, base::BindRepeating(&T::New));
|
||||
if (std::is_base_of<EventEmitterMixin<T>, T>::value) {
|
||||
constructor->Inherit(
|
||||
gin_helper::internal::GetEventEmitterTemplate(isolate));
|
||||
}
|
||||
constructor->InstanceTemplate()->SetInternalFieldCount(
|
||||
gin::kNumberOfInternalFields);
|
||||
constructor->SetClassName(gin::StringToV8(isolate, T::GetClassName()));
|
||||
T::FillObjectTemplate(isolate, constructor->PrototypeTemplate());
|
||||
data->SetObjectTemplate(wrapper_info, constructor->InstanceTemplate());
|
||||
data->SetFunctionTemplate(wrapper_info, constructor);
|
||||
}
|
||||
return constructor->GetFunction(context).ToLocalChecked();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "base/containers/span.h"
|
||||
#include "gin/converter.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/common/gin_converters/std_converter.h" // for ConvertToV8(iso, &&)
|
||||
#include "shell/common/gin_helper/wrappable.h"
|
||||
|
||||
|
@ -76,6 +77,28 @@ v8::Local<v8::Value> CallMethod(gin_helper::DeprecatedWrappable<T>* object,
|
|||
return CallMethod(isolate, object, method_name, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
v8::Local<v8::Value> CallMethod(v8::Isolate* isolate,
|
||||
gin::Wrappable<T>* object,
|
||||
const char* method_name,
|
||||
Args&&... args) {
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
v8::Local<v8::Object> v8_object;
|
||||
if (object->GetWrapper(isolate).ToLocal(&v8_object))
|
||||
return scope.Escape(CustomEmit(isolate, v8_object, method_name,
|
||||
std::forward<Args>(args)...));
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
v8::Local<v8::Value> CallMethod(gin::Wrappable<T>* object,
|
||||
const char* method_name,
|
||||
Args&&... args) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
return CallMethod(isolate, object, method_name, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace gin_helper
|
||||
|
||||
#endif // ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_CALLER_H_
|
||||
|
|
|
@ -17,7 +17,7 @@ gin::DeprecatedWrapperInfo kWrapperInfo = {gin::kEmbedderNativeGin};
|
|||
v8::Local<v8::FunctionTemplate> GetEventEmitterTemplate(v8::Isolate* isolate) {
|
||||
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
||||
v8::Local<v8::FunctionTemplate> tmpl =
|
||||
data->GetFunctionTemplate(&kWrapperInfo);
|
||||
data->DeprecatedGetFunctionTemplate(&kWrapperInfo);
|
||||
|
||||
if (tmpl.IsEmpty()) {
|
||||
tmpl = v8::FunctionTemplate::New(isolate);
|
||||
|
@ -35,7 +35,7 @@ v8::Local<v8::FunctionTemplate> GetEventEmitterTemplate(v8::Isolate* isolate) {
|
|||
->SetPrototypeV2(context, eventemitter_prototype)
|
||||
.ToChecked());
|
||||
|
||||
data->SetFunctionTemplate(&kWrapperInfo, tmpl);
|
||||
data->DeprecatedSetFunctionTemplate(&kWrapperInfo, tmpl);
|
||||
}
|
||||
|
||||
return tmpl;
|
||||
|
|
|
@ -81,6 +81,7 @@ class CallbackHolderBase {
|
|||
|
||||
// gin::PerIsolateData::DisposeObserver
|
||||
void OnBeforeDispose(v8::Isolate* isolate) override;
|
||||
void OnBeforeMicrotasksRunnerDispose(v8::Isolate* isolate) override {}
|
||||
void OnDisposed() override;
|
||||
|
||||
private:
|
||||
|
|
36
shell/common/gin_helper/self_keep_alive.h
Normal file
36
shell/common/gin_helper/self_keep_alive.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2025 Microsoft, GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_SELF_KEEP_ALIVE_H_
|
||||
#define ELECTRON_SHELL_COMMON_GIN_HELPER_SELF_KEEP_ALIVE_H_
|
||||
|
||||
#include "gin/weak_cell.h"
|
||||
|
||||
namespace gin_helper {
|
||||
|
||||
// Based on third_party/blink/renderer/platform/heap/self_keep_alive.h
|
||||
template <typename Self>
|
||||
class SelfKeepAlive final {
|
||||
GIN_DISALLOW_NEW();
|
||||
|
||||
public:
|
||||
explicit SelfKeepAlive(Self* self) : keep_alive_(self) {}
|
||||
|
||||
SelfKeepAlive& operator=(Self* self) {
|
||||
DCHECK(!keep_alive_ || keep_alive_.Get() == self);
|
||||
keep_alive_ = self;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Clear() { keep_alive_.Clear(); }
|
||||
|
||||
explicit operator bool() const { return keep_alive_; }
|
||||
|
||||
private:
|
||||
cppgc::Persistent<Self> keep_alive_;
|
||||
};
|
||||
|
||||
} // namespace gin_helper
|
||||
|
||||
#endif // ELECTRON_SHELL_COMMON_GIN_HELPER_SELF_KEEP_ALIVE_H_
|
|
@ -37,19 +37,19 @@ class Wrappable : public WrappableBase {
|
|||
isolate, base::BindRepeating(&internal::InvokeNew<Sig>, constructor));
|
||||
templ->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
T::BuildPrototype(isolate, templ);
|
||||
gin::PerIsolateData::From(isolate)->SetFunctionTemplate(&kWrapperInfo,
|
||||
templ);
|
||||
gin::PerIsolateData::From(isolate)->DeprecatedSetFunctionTemplate(
|
||||
&kWrapperInfo, templ);
|
||||
}
|
||||
|
||||
static v8::Local<v8::FunctionTemplate> GetConstructor(v8::Isolate* isolate) {
|
||||
// Fill the object template.
|
||||
auto* data = gin::PerIsolateData::From(isolate);
|
||||
auto templ = data->GetFunctionTemplate(&kWrapperInfo);
|
||||
auto templ = data->DeprecatedGetFunctionTemplate(&kWrapperInfo);
|
||||
if (templ.IsEmpty()) {
|
||||
templ = v8::FunctionTemplate::New(isolate);
|
||||
templ->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
T::BuildPrototype(isolate, templ);
|
||||
data->SetFunctionTemplate(&kWrapperInfo, templ);
|
||||
data->DeprecatedSetFunctionTemplate(&kWrapperInfo, templ);
|
||||
}
|
||||
return templ;
|
||||
}
|
||||
|
|
|
@ -27,19 +27,53 @@ describe('cpp heap', () => {
|
|||
|
||||
it('should record as node in heap snapshot', async () => {
|
||||
const { remotely } = await startRemoteControlApp(['--expose-internals']);
|
||||
const [nodeCount, hasPersistentParent] = await remotely(async (heap: string) => {
|
||||
const result = await remotely(async (heap: string, snapshotHelper: string) => {
|
||||
const { recordState } = require(heap);
|
||||
const { containsRetainingPath } = require(snapshotHelper);
|
||||
const state = recordState();
|
||||
const rootNodes = state.snapshot.filter(
|
||||
(node: any) => node.name === 'Electron / App' && node.type !== 'string');
|
||||
const hasParent = rootNodes.some((node: any) => node.incomingEdges.some(
|
||||
(edge: any) => {
|
||||
return edge.type === 'element' && edge.from.name === 'C++ Persistent roots';
|
||||
}));
|
||||
return [rootNodes.length, hasParent];
|
||||
}, path.join(__dirname, '../../third_party/electron_node/test/common/heap'));
|
||||
expect(nodeCount).to.equal(1);
|
||||
expect(hasPersistentParent).to.be.true();
|
||||
return containsRetainingPath(state.snapshot, ['C++ Persistent roots', 'Electron / App']);
|
||||
}, path.join(__dirname, '../../third_party/electron_node/test/common/heap'),
|
||||
path.join(__dirname, 'lib', 'heapsnapshot-helpers.js'));
|
||||
expect(result).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('session module', () => {
|
||||
it('should record as node in heap snapshot', async () => {
|
||||
const { remotely } = await startRemoteControlApp(['--expose-internals']);
|
||||
const result = await remotely(async (heap: string, snapshotHelper: string) => {
|
||||
const { session, BrowserWindow } = require('electron');
|
||||
const { once } = require('node:events');
|
||||
const assert = require('node:assert');
|
||||
const { recordState } = require(heap);
|
||||
const { containsRetainingPath } = require(snapshotHelper);
|
||||
const session1 = session.defaultSession;
|
||||
console.log(session1.getStoragePath());
|
||||
const session2 = session.fromPartition('cppheap1');
|
||||
const session3 = session.fromPartition('cppheap1');
|
||||
const session4 = session.fromPartition('cppheap2');
|
||||
console.log(session2.cookies);
|
||||
assert.strictEqual(session2, session3);
|
||||
assert.notStrictEqual(session2, session4);
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
session: session.fromPartition('cppheap1')
|
||||
}
|
||||
});
|
||||
await w.loadURL('about:blank');
|
||||
const state = recordState();
|
||||
const isClosed = once(w, 'closed');
|
||||
w.destroy();
|
||||
await isClosed;
|
||||
const numSessions = containsRetainingPath(state.snapshot, ['C++ Persistent roots', 'Electron / Session'], {
|
||||
occurrences: 4
|
||||
});
|
||||
const canTraceJSReferences = containsRetainingPath(state.snapshot, ['C++ Persistent roots', 'Electron / Session', 'Cookies']);
|
||||
return numSessions && canTraceJSReferences;
|
||||
}, path.join(__dirname, '../../third_party/electron_node/test/common/heap'),
|
||||
path.join(__dirname, 'lib', 'heapsnapshot-helpers.js'));
|
||||
expect(result).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
25
spec/lib/heapsnapshot-helpers.js
Normal file
25
spec/lib/heapsnapshot-helpers.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
export function containsRetainingPath (snapshot, retainingPath, options) {
|
||||
let root = snapshot.filter(
|
||||
(node) => node.name === retainingPath[0] && node.type !== 'string');
|
||||
for (let i = 1; i < retainingPath.length; i++) {
|
||||
const needle = retainingPath[i];
|
||||
const newRoot = [];
|
||||
for (const node of root) {
|
||||
for (let j = 0; j < node.outgoingEdges.length; j++) {
|
||||
const child = node.outgoingEdges[j].to;
|
||||
if (child.type === 'string') continue;
|
||||
if (child.name === needle) {
|
||||
newRoot.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!newRoot.length) {
|
||||
console.log(`No retaining path found for ${needle}`);
|
||||
return false;
|
||||
}
|
||||
root = newRoot;
|
||||
}
|
||||
return options?.occurrances
|
||||
? root.length === options.occurrances
|
||||
: true;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue