Repository: WebKit/WebKit
Pull request #43928: Support memory attribution for Model Element
Author: login: amarchenko
Created: 2025-04-10T23:34:46Z | Merged: 2025-04-12T00:18:00Z

#### d1807b80b6c27f7300887b4cd0b587931605fa6f
<pre>
Support memory attribution for Model Element
<a href="https://bugs.webkit.org/show_bug.cgi?id=291387">https://bugs.webkit.org/show_bug.cgi?id=291387</a>
<a href="https://rdar.apple.com/133812421">rdar://133812421</a>

Reviewed by Ada Chan and Mike Wyrzykowski.

This commit adds the necessary infrastructure to support memory attribution
in RealityKit within the ModelProcess for the corresponding Web Content Process.
Due to strict permissions the Model Process can not make the calls for
attribution directly, therefore it is originated in the UI Process and
propagated to the GPU Process.
Also, the change depends on availability of task identity token, hence unavailable
on the simulator.

* Source/WebKit/GPUProcess/GPUProcess.h:
* Source/WebKit/GPUProcess/GPUProcess.messages.in:
* Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm:
(WebKit::GPUProcess::createMemoryAttributionIDForTask):
(WebKit::GPUProcess::unregisterMemoryAttributionID):
Methods to to create and clean up attribution IDs.
GPU Process entitled to do so.

* Source/WebKit/ModelProcess/ModelConnectionToWebProcess.cpp:
(WebKit::ModelConnectionToWebProcess::create):
(WebKit::ModelConnectionToWebProcess::ModelConnectionToWebProcess):
* Source/WebKit/ModelProcess/ModelConnectionToWebProcess.h:
(WebKit::ModelConnectionToWebProcess::attributionTaskID const):
Stores and tracks attribution ID for the corresponding Web Process.
Has an accessor to the ID for ModelProcessModelPlayerManagerProxy.

* Source/WebKit/ModelProcess/ModelProcess.cpp:
(WebKit::ModelProcess::createModelConnectionToWebProcess):
* Source/WebKit/ModelProcess/ModelProcess.h:
* Source/WebKit/ModelProcess/ModelProcess.messages.in:
Accepts and forwards attribution ID.

* Source/WebKit/ModelProcess/ModelProcessModelPlayerManagerProxy.cpp:
(WebKit::ModelProcessModelPlayerManagerProxy::createModelPlayer):
* Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h:
* Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm:
(WebKit::RKModelLoaderUSD::load):
(WebKit::loadREModelUsingRKUSDLoader):
(WebKit::ModelProcessModelPlayerProxy::create):
(WebKit::ModelProcessModelPlayerProxy::ModelProcessModelPlayerProxy):
(WebKit::ModelProcessModelPlayerProxy::load):
RKModelLoaderUSD includes attribution ID for load operations.

* Source/WebKit/Scripts/process-entitlements.sh:
Added com.apple.surfboard.shared-simulation-memory-attribution entitlement

* Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp:
(WebKit::GPUProcessProxy::createMemoryAttributionIDForTask):
(WebKit::GPUProcessProxy::unregisterMemoryAttributionID):
* Source/WebKit/UIProcess/GPU/GPUProcessProxy.h:
* Source/WebKit/UIProcess/Model/ModelProcessProxy.cpp:
(WebKit::ModelProcessProxy::createModelProcessConnection):
* Source/WebKit/UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::disconnectProcess):
* Source/WebKit/UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::createMemoryAttributionIDIfNeeded):
(WebKit::WebProcessProxy::unregisterMemoryAttributionIDIfNeeded):
* Source/WebKit/UIProcess/WebProcessProxy.h:
Has methods to lazily create and clean up attribution IDs.

* Source/WebKit/WebKitSwift/RealityKit/RKEntity.swift:
(WKSRKEntity.load(from:attributionTaskId:completionHandler:)):
(WKSRKEntity.load(from:completionHandler:)): Deleted.
* Source/WebKit/WebKitSwift/RealityKit/RealityKitBridging.h:
Entity initialization now includes memory attribution option.

Canonical link: <a href="https://commits.webkit.org/293610@main">https://commits.webkit.org/293610@main</a>
</pre>
<!--EWS-Status-Bubble-Start-->
https://github.com/WebKit/WebKit/commit/8e7967fcf84f663c88f4c46327185c0b3432c503

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/99409 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/19059 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/9312 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/104540 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/50010 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/19347 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/27492 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/34/builds/75659 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/32753 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/102416 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/14714 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/89757 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/56018 "Passed tests") | 
| [✅ 🧪 webkitpy](https://ews-build.webkit.org/#/builders/6/builds/98882 "Passed tests") | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/14509 "Passed tests") | | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/49370 "Built successfully") | 
| | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/13/builds/84432 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | [  ~~🧪 mac-wk2~~](https://ews-build.webkit.org/#/builders/136/builds/7827 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/106898 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/26523 "Built successfully") | [  ~~🧪 mac-AS-debug-wk2~~](https://ews-build.webkit.org/#/builders/122/builds/19349 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/1/builds/84618 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/26885 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/85961 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/84132 "Passed tests") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/21339 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/28803 "Passed tests") | [  ~~🧪 mac-intel-wk2~~](https://ews-build.webkit.org/#/builders/137/builds/6499 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/20266 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/26463 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/31664 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/26283 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/29596 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/27850 "Built successfully") | | | 
<!--EWS-Status-Bubble-End-->


Diff:
diff --git a/Source/WebKit/GPUProcess/GPUProcess.h b/Source/WebKit/GPUProcess/GPUProcess.h
index 34d7bfb2167f..f83d3cfd1dff 100644
--- a/Source/WebKit/GPUProcess/GPUProcess.h
+++ b/Source/WebKit/GPUProcess/GPUProcess.h
@@ -163,6 +163,10 @@ class GPUProcess final : public AuxiliaryProcess, public ThreadSafeRefCounted<GP
 
 #if PLATFORM(VISION) && ENABLE(MODEL_PROCESS)
     void requestSharedSimulationConnection(CoreIPCAuditToken&&, CompletionHandler<void(std::optional<IPC::SharedFileHandle>)>&&);
+#if HAVE(TASK_IDENTITY_TOKEN)
+    void createMemoryAttributionIDForTask(WebCore::ProcessIdentity, CompletionHandler<void(const std::optional<String>&)>&&);
+    void unregisterMemoryAttributionID(const String&, CompletionHandler<void()>&&);
+#endif
 #endif
 
 private:
diff --git a/Source/WebKit/GPUProcess/GPUProcess.messages.in b/Source/WebKit/GPUProcess/GPUProcess.messages.in
index 308e3ab521a0..7237c83e740f 100644
--- a/Source/WebKit/GPUProcess/GPUProcess.messages.in
+++ b/Source/WebKit/GPUProcess/GPUProcess.messages.in
@@ -101,6 +101,10 @@ messages -> GPUProcess : AuxiliaryProcess {
 #endif
 #if PLATFORM(VISION) && ENABLE(MODEL_PROCESS)
     RequestSharedSimulationConnection(struct WebKit::CoreIPCAuditToken modelProcessAuditToken) -> (std::optional<IPC::SharedFileHandle> sharedSimulationConnection)
+#if HAVE(TASK_IDENTITY_TOKEN)
+    CreateMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity) -> (std::optional<String> completionHandler)
+    UnregisterMemoryAttributionID(String attributionID) -> ()
+#endif
 #endif
 }
 
diff --git a/Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm b/Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
index f79e13aa2206..4404bc8de5cf 100644
--- a/Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
+++ b/Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
@@ -168,6 +168,35 @@
         completionHandler(IPC::SharedFileHandle::create(FileSystem::FileHandle::adopt([sharedSimulationConnection fileDescriptor])));
     });
 }
+
+#if HAVE(TASK_IDENTITY_TOKEN)
+void GPUProcess::createMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity, CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->createMemoryAttributionIDForTask(processIdentity.taskIdToken(), [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<NSString> attributionTaskID, RetainPtr<id> appService) mutable {
+        if (!attributionTaskID) {
+            RELEASE_LOG_ERROR(ModelElement, "GPUProcess: Memory attribution ID request failed");
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID request succeeded");
+        completionHandler(String(attributionTaskID.get()));
+    });
+}
+
+void GPUProcess::unregisterMemoryAttributionID(const String& attributionID, CompletionHandler<void()>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->unregisterMemoryAttributionID(attributionID, [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<id> appService) mutable {
+        if (appService)
+            RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID unregistration succeeded");
+        else
+            RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID unregistration failed");
+        completionHandler();
+    });
+}
+#endif
 #endif
 
 } // namespace WebKit
diff --git a/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.cpp b/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.cpp
index 7a54f935c28e..327894c1e9c4 100644
--- a/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.cpp
+++ b/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.cpp
@@ -55,12 +55,24 @@
 namespace WebKit {
 using namespace WebCore;
 
-Ref<ModelConnectionToWebProcess> ModelConnectionToWebProcess::create(ModelProcess& modelProcess, WebCore::ProcessIdentifier webProcessIdentifier, PAL::SessionID sessionID, IPC::Connection::Handle&& connectionHandle, ModelProcessConnectionParameters&& parameters)
+Ref<ModelConnectionToWebProcess> ModelConnectionToWebProcess::create(
+    ModelProcess& modelProcess,
+    WebCore::ProcessIdentifier webProcessIdentifier,
+    PAL::SessionID sessionID,
+    IPC::Connection::Handle&& connectionHandle,
+    ModelProcessConnectionParameters&& parameters,
+    const std::optional<String>& attributionTaskID)
 {
-    return adoptRef(*new ModelConnectionToWebProcess(modelProcess, webProcessIdentifier, sessionID, WTFMove(connectionHandle), WTFMove(parameters)));
+    return adoptRef(*new ModelConnectionToWebProcess(modelProcess, webProcessIdentifier, sessionID, WTFMove(connectionHandle), WTFMove(parameters), attributionTaskID));
 }
 
-ModelConnectionToWebProcess::ModelConnectionToWebProcess(ModelProcess& modelProcess, WebCore::ProcessIdentifier webProcessIdentifier, PAL::SessionID sessionID, IPC::Connection::Handle&& connectionHandle, ModelProcessConnectionParameters&& parameters)
+ModelConnectionToWebProcess::ModelConnectionToWebProcess(
+    ModelProcess& modelProcess,
+    WebCore::ProcessIdentifier webProcessIdentifier,
+    PAL::SessionID sessionID,
+    IPC::Connection::Handle&& connectionHandle,
+    ModelProcessConnectionParameters&& parameters,
+    const std::optional<String>& attributionTaskID)
     : m_modelProcessModelPlayerManagerProxy(ModelProcessModelPlayerManagerProxy::create(*this))
     , m_connection(IPC::Connection::createClientConnection(IPC::Connection::Identifier { WTFMove(connectionHandle) }))
     , m_modelProcess(modelProcess)
@@ -73,6 +85,7 @@ ModelConnectionToWebProcess::ModelConnectionToWebProcess(ModelProcess& modelProc
 #if ENABLE(IPC_TESTING_API)
     , m_ipcTester(IPCTester::create())
 #endif
+    , m_attributionTaskID(attributionTaskID)
     , m_sharedPreferencesForWebProcess(WTFMove(parameters.sharedPreferencesForWebProcess))
 {
     RELEASE_ASSERT(RunLoop::isMain());
diff --git a/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.h b/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.h
index f4d866318be1..d5673800dff9 100644
--- a/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.h
+++ b/Source/WebKit/ModelProcess/ModelConnectionToWebProcess.h
@@ -71,7 +71,7 @@ class ModelConnectionToWebProcess
     WTF_MAKE_FAST_ALLOCATED;
     WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(ModelConnectionToWebProcess);
 public:
-    static Ref<ModelConnectionToWebProcess> create(ModelProcess&, WebCore::ProcessIdentifier, PAL::SessionID, IPC::Connection::Handle&&, ModelProcessConnectionParameters&&);
+    static Ref<ModelConnectionToWebProcess> create(ModelProcess&, WebCore::ProcessIdentifier, PAL::SessionID, IPC::Connection::Handle&&, ModelProcessConnectionParameters&&, const std::optional<String>&);
     virtual ~ModelConnectionToWebProcess();
 
     void ref() const final { ThreadSafeRefCounted::ref(); }
@@ -104,8 +104,10 @@ class ModelConnectionToWebProcess
 
     bool isAlwaysOnLoggingAllowed() const;
 
+    const std::optional<String> attributionTaskID() const { return m_attributionTaskID; };
+
 private:
-    ModelConnectionToWebProcess(ModelProcess&, WebCore::ProcessIdentifier, PAL::SessionID, IPC::Connection::Handle&&, ModelProcessConnectionParameters&&);
+    ModelConnectionToWebProcess(ModelProcess&, WebCore::ProcessIdentifier, PAL::SessionID, IPC::Connection::Handle&&, ModelProcessConnectionParameters&&, const std::optional<String>&);
 
 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
     void createVisibilityPropagationContextForPage(WebPageProxyIdentifier, WebCore::PageIdentifier, bool canShowWhileLocked);
@@ -147,6 +149,8 @@ class ModelConnectionToWebProcess
     const Ref<IPCTester> m_ipcTester;
 #endif
 
+    std::optional<String> m_attributionTaskID;
+
     SharedPreferencesForWebProcess m_sharedPreferencesForWebProcess;
 };
 
diff --git a/Source/WebKit/ModelProcess/ModelProcess.cpp b/Source/WebKit/ModelProcess/ModelProcess.cpp
index e353501c551d..086cca0a63f6 100644
--- a/Source/WebKit/ModelProcess/ModelProcess.cpp
+++ b/Source/WebKit/ModelProcess/ModelProcess.cpp
@@ -76,7 +76,13 @@ ModelProcess::ModelProcess(AuxiliaryProcessInitializationParameters&& parameters
 
 ModelProcess::~ModelProcess() = default;
 
-void ModelProcess::createModelConnectionToWebProcess(WebCore::ProcessIdentifier identifier, PAL::SessionID sessionID, IPC::Connection::Handle&& connectionHandle, ModelProcessConnectionParameters&& parameters, CompletionHandler<void()>&& completionHandler)
+void ModelProcess::createModelConnectionToWebProcess(
+    WebCore::ProcessIdentifier identifier,
+    PAL::SessionID sessionID,
+    IPC::Connection::Handle&& connectionHandle,
+    ModelProcessConnectionParameters&& parameters,
+    const std::optional<String>& attributionTaskID,
+    CompletionHandler<void()>&& completionHandler)
 {
     RELEASE_LOG(Process, "%p - ModelProcess::createModelConnectionToWebProcess: processIdentifier=%" PRIu64, this, identifier.toUInt64());
 
@@ -98,7 +104,7 @@ void ModelProcess::createModelConnectionToWebProcess(WebCore::ProcessIdentifier
     });
 #endif
 
-    auto newConnection = ModelConnectionToWebProcess::create(*this, identifier, sessionID, WTFMove(connectionHandle), WTFMove(parameters));
+    auto newConnection = ModelConnectionToWebProcess::create(*this, identifier, sessionID, WTFMove(connectionHandle), WTFMove(parameters), attributionTaskID);
 
 #if ENABLE(IPC_TESTING_API)
     if (parameters.ignoreInvalidMessageForTesting)
diff --git a/Source/WebKit/ModelProcess/ModelProcess.h b/Source/WebKit/ModelProcess/ModelProcess.h
index beacd75d0251..945580c0fd07 100644
--- a/Source/WebKit/ModelProcess/ModelProcess.h
+++ b/Source/WebKit/ModelProcess/ModelProcess.h
@@ -100,7 +100,7 @@ class ModelProcess final : public AuxiliaryProcess, public ThreadSafeRefCounted<
 
     // Message Handlers
     void initializeModelProcess(ModelProcessCreationParameters&&, CompletionHandler<void()>&&);
-    void createModelConnectionToWebProcess(WebCore::ProcessIdentifier, PAL::SessionID, IPC::Connection::Handle&&, ModelProcessConnectionParameters&&, CompletionHandler<void()>&&);
+    void createModelConnectionToWebProcess(WebCore::ProcessIdentifier, PAL::SessionID, IPC::Connection::Handle&&, ModelProcessConnectionParameters&&, const std::optional<String>& attributionTaskID, CompletionHandler<void()>&&);
     void sharedPreferencesForWebProcessDidChange(WebCore::ProcessIdentifier, SharedPreferencesForWebProcess&&, CompletionHandler<void()>&&);
     void addSession(PAL::SessionID);
     void removeSession(PAL::SessionID);
diff --git a/Source/WebKit/ModelProcess/ModelProcess.messages.in b/Source/WebKit/ModelProcess/ModelProcess.messages.in
index 6e34701d9a3d..c1e3be12090e 100644
--- a/Source/WebKit/ModelProcess/ModelProcess.messages.in
+++ b/Source/WebKit/ModelProcess/ModelProcess.messages.in
@@ -30,7 +30,7 @@
 messages -> ModelProcess : AuxiliaryProcess {
     InitializeModelProcess(struct WebKit::ModelProcessCreationParameters processCreationParameters) -> ()
 
-    CreateModelConnectionToWebProcess(WebCore::ProcessIdentifier processIdentifier, PAL::SessionID sessionID, IPC::ConnectionHandle connectionHandle, struct WebKit::ModelProcessConnectionParameters parameters) -> () AllowedWhenWaitingForSyncReply
+    CreateModelConnectionToWebProcess(WebCore::ProcessIdentifier processIdentifier, PAL::SessionID sessionID, IPC::ConnectionHandle connectionHandle, struct WebKit::ModelProcessConnectionParameters parameters, std::optional<String> attributionTaskID) -> () AllowedWhenWaitingForSyncReply
     SharedPreferencesForWebProcessDidChange(WebCore::ProcessIdentifier processIdentifier, struct WebKit::SharedPreferencesForWebProcess sharedPreferencesForWebProcess) -> ()
 
     PrepareToSuspend(bool isSuspensionImminent, MonotonicTime estimatedSuspendTime) -> ()
diff --git a/Source/WebKit/ModelProcess/ModelProcessModelPlayerManagerProxy.cpp b/Source/WebKit/ModelProcess/ModelProcessModelPlayerManagerProxy.cpp
index bfbc9b446e5c..cdb3330d84ee 100644
--- a/Source/WebKit/ModelProcess/ModelProcessModelPlayerManagerProxy.cpp
+++ b/Source/WebKit/ModelProcess/ModelProcessModelPlayerManagerProxy.cpp
@@ -69,7 +69,7 @@ void ModelProcessModelPlayerManagerProxy::createModelPlayer(WebCore::ModelPlayer
     ASSERT(m_modelConnectionToWebProcess);
     ASSERT(!m_proxies.contains(identifier));
 
-    auto proxy = ModelProcessModelPlayerProxy::create(*this, identifier, m_modelConnectionToWebProcess->protectedConnection());
+    auto proxy = ModelProcessModelPlayerProxy::create(*this, identifier, m_modelConnectionToWebProcess->protectedConnection(), m_modelConnectionToWebProcess->attributionTaskID());
     m_proxies.add(identifier, WTFMove(proxy));
 }
 
diff --git a/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h b/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h
index 7e972dfdb830..6045741298aa 100644
--- a/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h
+++ b/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h
@@ -67,7 +67,7 @@ class ModelProcessModelPlayerProxy final
     , private IPC::MessageReceiver {
     WTF_MAKE_TZONE_ALLOCATED(ModelProcessModelPlayerProxy);
 public:
-    static Ref<ModelProcessModelPlayerProxy> create(ModelProcessModelPlayerManagerProxy&, WebCore::ModelPlayerIdentifier, Ref<IPC::Connection>&&);
+    static Ref<ModelProcessModelPlayerProxy> create(ModelProcessModelPlayerManagerProxy&, WebCore::ModelPlayerIdentifier, Ref<IPC::Connection>&&, const std::optional<String>&);
     ~ModelProcessModelPlayerProxy();
 
     void ref() const final { WebCore::ModelPlayer::ref(); }
@@ -140,7 +140,7 @@ class ModelProcessModelPlayerProxy final
     USING_CAN_MAKE_WEAKPTR(WebCore::REModelLoaderClient);
 
 private:
-    ModelProcessModelPlayerProxy(ModelProcessModelPlayerManagerProxy&, WebCore::ModelPlayerIdentifier, Ref<IPC::Connection>&&);
+    ModelProcessModelPlayerProxy(ModelProcessModelPlayerManagerProxy&, WebCore::ModelPlayerIdentifier, Ref<IPC::Connection>&&, const std::optional<String>&);
 
     void computeTransform(bool);
     void applyEnvironmentMapDataAndRelease();
@@ -179,6 +179,8 @@ class ModelProcessModelPlayerProxy final
     // For interactions
     RetainPtr<WKStageModeInteractionDriver> m_stageModeInteractionDriver;
     WebCore::StageModeOperation m_stageModeOperation { WebCore::StageModeOperation::None };
+
+    std::optional<String> m_attributionTaskID;
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm b/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm
index da7ea6cf1baa..0d3ceccc52c8 100644
--- a/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm
+++ b/Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm
@@ -128,9 +128,9 @@ REEntityRef rootEntity() const final
 
 class RKModelLoaderUSD final : public WebCore::REModelLoader, public CanMakeWeakPtr<RKModelLoaderUSD> {
 public:
-    static Ref<RKModelLoaderUSD> create(Model& model, REModelLoaderClient& client)
+    static Ref<RKModelLoaderUSD> create(Model& model, const std::optional<String>& attributionTaskID, REModelLoaderClient& client)
     {
-        return adoptRef(*new RKModelLoaderUSD(model, client));
+        return adoptRef(*new RKModelLoaderUSD(model, attributionTaskID, client));
     }
 
     virtual ~RKModelLoaderUSD() = default;
@@ -140,9 +140,10 @@ REEntityRef rootEntity() const final
     bool isCanceled() const { return m_canceled; }
 
 private:
-    RKModelLoaderUSD(Model& model, REModelLoaderClient& client)
+    RKModelLoaderUSD(Model& model, const std::optional<String>& attributionTaskID, REModelLoaderClient& client)
         : m_canceled { false }
         , m_model { model }
+        , m_attributionTaskID { attributionTaskID }
         , m_client { client }
     {
     }
@@ -174,6 +175,7 @@ void didFail(ResourceError error)
     bool m_canceled { false };
 
     Ref<Model> m_model;
+    std::optional<String> m_attributionTaskID;
     WeakPtr<REModelLoaderClient> m_client;
 };
 
@@ -187,7 +189,10 @@ static ResourceError toResourceError(String payload, Model& model)
 
 void RKModelLoaderUSD::load()
 {
-    [getWKSRKEntityClass() loadFromData:m_model->data()->createNSData().get() completionHandler:makeBlockPtr([weakThis = WeakPtr { *this }] (WKSRKEntity *entity) mutable {
+    NSString *attributionID = nil;
+    if (m_attributionTaskID.has_value())
+        attributionID = m_attributionTaskID.value();
+    [getWKSRKEntityClass() loadFromData:m_model->data()->createNSData().get() withAttributionTaskID:attributionID completionHandler:makeBlockPtr([weakThis = WeakPtr { *this }] (WKSRKEntity *entity) mutable {
         RefPtr protectedThis = weakThis.get();
         if (!protectedThis)
             return;
@@ -201,9 +206,9 @@ static ResourceError toResourceError(String payload, Model& model)
     }).get()];
 }
 
-static Ref<REModelLoader> loadREModelUsingRKUSDLoader(Model& model, REModelLoaderClient& client)
+static Ref<REModelLoader> loadREModelUsingRKUSDLoader(Model& model, const std::optional<String>& attributionTaskID, REModelLoaderClient& client)
 {
-    auto loader = RKModelLoaderUSD::create(model, client);
+    auto loader = RKModelLoaderUSD::create(model, attributionTaskID, client);
 
     dispatch_async(dispatch_get_main_queue(), [loader] () mutable {
         loader->load();
@@ -214,15 +219,16 @@ static ResourceError toResourceError(String payload, Model& model)
 
 WTF_MAKE_TZONE_ALLOCATED_IMPL(ModelProcessModelPlayerProxy);
 
-Ref<ModelProcessModelPlayerProxy> ModelProcessModelPlayerProxy::create(ModelProcessModelPlayerManagerProxy& manager, WebCore::ModelPlayerIdentifier identifier, Ref<IPC::Connection>&& connection)
+Ref<ModelProcessModelPlayerProxy> ModelProcessModelPlayerProxy::create(ModelProcessModelPlayerManagerProxy& manager, WebCore::ModelPlayerIdentifier identifier, Ref<IPC::Connection>&& connection, const std::optional<String>& attributionTaskID)
 {
-    return adoptRef(*new ModelProcessModelPlayerProxy(manager, identifier, WTFMove(connection)));
+    return adoptRef(*new ModelProcessModelPlayerProxy(manager, identifier, WTFMove(connection), attributionTaskID));
 }
 
-ModelProcessModelPlayerProxy::ModelProcessModelPlayerProxy(ModelProcessModelPlayerManagerProxy& manager, WebCore::ModelPlayerIdentifier identifier, Ref<IPC::Connection>&& connection)
+ModelProcessModelPlayerProxy::ModelProcessModelPlayerProxy(ModelProcessModelPlayerManagerProxy& manager, WebCore::ModelPlayerIdentifier identifier, Ref<IPC::Connection>&& connection, const std::optional<String>& attributionTaskID)
     : m_id(identifier)
     , m_webProcessConnection(WTFMove(connection))
     , m_manager(manager)
+    , m_attributionTaskID(attributionTaskID)
 {
     RELEASE_LOG(ModelElement, "%p - ModelProcessModelPlayerProxy initialized id=%" PRIu64, this, identifier.toUInt64());
     m_objCAdapter = adoptNS([[WKModelProcessModelPlayerProxyObjCAdapter alloc] initWithModelProcessModelPlayerProxy:*this]);
@@ -553,7 +559,7 @@ static CGFloat effectivePointsPerMeter(CALayer *caLayer)
     WKREEngine::shared().runWithSharedScene([this, protectedThis = Ref { *this }, model = Ref { model }] (RESceneRef scene) {
         m_scene = scene;
         if ([getWKSRKEntityClass() isLoadFromDataAvailable])
-            m_loader = loadREModelUsingRKUSDLoader(model.get(), *this);
+            m_loader = loadREModelUsingRKUSDLoader(model.get(), m_attributionTaskID, *this);
         else
             m_loader = WebCore::loadREModel(model.get(), *this);
     });
diff --git a/Source/WebKit/Scripts/process-entitlements.sh b/Source/WebKit/Scripts/process-entitlements.sh
index 3e7c888dd7b8..8b822b05d0ab 100755
--- a/Source/WebKit/Scripts/process-entitlements.sh
+++ b/Source/WebKit/Scripts/process-entitlements.sh
@@ -561,6 +561,7 @@ fi
 if [[ "${WK_PLATFORM_NAME}" == xros ]]; then
     plistbuddy Add :com.apple.surfboard.application-service-client bool YES
     plistbuddy Add :com.apple.surfboard.shared-simulation-connection-request bool YES
+    plistbuddy Add :com.apple.surfboard.shared-simulation-memory-attribution bool YES
 fi
 
     plistbuddy Add :com.apple.developer.hardened-process bool YES
diff --git a/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp b/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp
index bda7a4a1b5c8..079ba72c57a3 100644
--- a/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp
@@ -915,6 +915,18 @@ void GPUProcessProxy::requestSharedSimulationConnection(audit_token_t modelProce
 {
     sendWithAsyncReply(Messages::GPUProcess::RequestSharedSimulationConnection { modelProcessAuditToken }, WTFMove(completionHandler));
 }
+
+#if HAVE(TASK_IDENTITY_TOKEN)
+void GPUProcessProxy::createMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity, CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    sendWithAsyncReply(Messages::GPUProcess::CreateMemoryAttributionIDForTask { WTFMove(processIdentity) }, WTFMove(completionHandler));
+}
+
+void GPUProcessProxy::unregisterMemoryAttributionID(const String& attributionID, CompletionHandler<void()>&& completionHandler)
+{
+    sendWithAsyncReply(Messages::GPUProcess::UnregisterMemoryAttributionID { attributionID }, WTFMove(completionHandler));
+}
+#endif
 #endif
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h b/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h
index 9d533d0cb6a7..b8abf132eeaf 100644
--- a/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h
+++ b/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h
@@ -171,6 +171,8 @@ class GPUProcessProxy final : public AuxiliaryProcessProxy {
 
 #if PLATFORM(VISION) && ENABLE(MODEL_PROCESS)
     void requestSharedSimulationConnection(audit_token_t, CompletionHandler<void(std::optional<IPC::SharedFileHandle>)>&&);
+    void createMemoryAttributionIDForTask(WebCore::ProcessIdentity, CompletionHandler<void(const std::optional<String>&)>&&);
+    void unregisterMemoryAttributionID(const String&, CompletionHandler<void()>&&);
 #endif
 
 private:
diff --git a/Source/WebKit/UIProcess/Model/ModelProcessProxy.cpp b/Source/WebKit/UIProcess/Model/ModelProcessProxy.cpp
index cd4843bceaae..8b058304c65c 100644
--- a/Source/WebKit/UIProcess/Model/ModelProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/Model/ModelProcessProxy.cpp
@@ -132,16 +132,39 @@ void ModelProcessProxy::processWillShutDown(IPC::Connection& connection)
 
 void ModelProcessProxy::createModelProcessConnection(WebProcessProxy& webProcessProxy, IPC::Connection::Handle&& connectionIdentifier, ModelProcessConnectionParameters&& parameters)
 {
+    auto createConnectionBlock = [this, &webProcessProxy](
+        IPC::Connection::Handle&& connectionIdentifier,
+        ModelProcessConnectionParameters&& parameters,
+        const std::optional<String>& attributionTaskID) {
+        sendWithAsyncReply(
+            Messages::ModelProcess::CreateModelConnectionToWebProcess {
+                webProcessProxy.coreProcessIdentifier(),
+                webProcessProxy.sessionID(),
+                WTFMove(connectionIdentifier),
+                WTFMove(parameters),
+                attributionTaskID
+            },
+            [this, weakThis = WeakPtr { *this }]() mutable {
+                if (!weakThis)
+                    return;
+                stopResponsivenessTimer();
+            }, 0, IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply);
+    };
+
     if (auto* store = webProcessProxy.websiteDataStore())
         addSession(*store);
 
     RELEASE_LOG(ProcessSuspension, "%p - ModelProcessProxy is taking a background assertion because a web process is requesting a connection", this);
     startResponsivenessTimer(UseLazyStop::No);
-    sendWithAsyncReply(Messages::ModelProcess::CreateModelConnectionToWebProcess { webProcessProxy.coreProcessIdentifier(), webProcessProxy.sessionID(), WTFMove(connectionIdentifier), WTFMove(parameters) }, [this, weakThis = WeakPtr { *this }]() mutable {
+#if HAVE(TASK_IDENTITY_TOKEN)
+    webProcessProxy.createMemoryAttributionIDIfNeeded([weakThis = WeakPtr { *this }, createConnectionBlock = WTFMove(createConnectionBlock), connectionIdentifier = WTFMove(connectionIdentifier), parameters = WTFMove(parameters)](const std::optional<String>& attributionTaskID) mutable {
         if (!weakThis)
             return;
-        stopResponsivenessTimer();
-    }, 0, IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply);
+        createConnectionBlock(WTFMove(connectionIdentifier), WTFMove(parameters), attributionTaskID);
+    });
+#else
+    createConnectionBlock(WTFMove(connectionIdentifier), WTFMove(parameters), std::nullopt);
+#endif
 }
 
 void ModelProcessProxy::sharedPreferencesForWebProcessDidChange(WebProcessProxy& webProcessProxy, SharedPreferencesForWebProcess&& sharedPreferencesForWebProcess, CompletionHandler<void()>&& completionHandler)
diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp
index 2d8b8c2f7532..7077b45b0a45 100644
--- a/Source/WebKit/UIProcess/WebProcessPool.cpp
+++ b/Source/WebKit/UIProcess/WebProcessPool.cpp
@@ -1149,6 +1149,10 @@ void WebProcessPool::disconnectProcess(WebProcessProxy& process)
     // Clearing everything causes assertion failures, so it's less trouble to skip that for now.
     Ref protectedProcess { process };
 
+#if ENABLE(MODEL_PROCESS) && HAVE(TASK_IDENTITY_TOKEN)
+    process.unregisterMemoryAttributionIDIfNeeded();
+#endif
+
     protectedBackForwardCache()->removeEntriesForProcess(process);
 
     if (process.isRunningWorkers())
diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp
index 9d842f70ba99..a4c61b73b4c3 100644
--- a/Source/WebKit/UIProcess/WebProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp
@@ -1217,6 +1217,42 @@ void WebProcessProxy::modelProcessExited(ProcessTerminationReason reason)
         page->modelProcessExited(reason);
 }
 
+#if HAVE(TASK_IDENTITY_TOKEN)
+void WebProcessProxy::createMemoryAttributionIDIfNeeded(CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    if (m_memoryAttributionID.has_value()) {
+        completionHandler(m_memoryAttributionID);
+        return;
+    }
+
+    GPUProcessProxy::getOrCreate()->createMemoryAttributionIDForTask(m_processIdentity, [this, weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler)]
+    (const std::optional<String>& attributionTaskID) mutable {
+        if (!weakThis)
+            return;
+
+        if (attributionTaskID.has_value()) {
+            WEBPROCESSPROXY_RELEASE_LOG(Process, "createMemoryAttributionIDIfNeeded: created memory attribution ID");
+            m_memoryAttributionID = attributionTaskID;
+        }
+
+        completionHandler(m_memoryAttributionID);
+    });
+
+}
+
+void WebProcessProxy::unregisterMemoryAttributionIDIfNeeded()
+{
+    if (!m_memoryAttributionID.has_value())
+        return;
+
+    GPUProcessProxy::getOrCreate()->unregisterMemoryAttributionID(m_memoryAttributionID.value(), [this, weakThis = WeakPtr { *this }]() mutable {
+        if (!weakThis)
+            return;
+
+        WEBPROCESSPROXY_RELEASE_LOG(Process, "unregisterMemoryAttributionIDIfNeeded: unregistered memory attribution ID");
+    });
+}
+#endif // HAVE(TASK_IDENTITY_TOKEN)
 #endif // ENABLE(MODEL_PROCESS)
 
 #if !PLATFORM(MAC)
diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h
index 4a92d9afbf20..471f1782a0de 100644
--- a/Source/WebKit/UIProcess/WebProcessProxy.h
+++ b/Source/WebKit/UIProcess/WebProcessProxy.h
@@ -456,6 +456,10 @@ class WebProcessProxy final : public AuxiliaryProcessProxy {
 #if ENABLE(MODEL_PROCESS)
     void modelProcessDidFinishLaunching();
     void modelProcessExited(ProcessTerminationReason);
+#if HAVE(TASK_IDENTITY_TOKEN)
+    void createMemoryAttributionIDIfNeeded(CompletionHandler<void(const std::optional<String>&)>&&);
+    void unregisterMemoryAttributionIDIfNeeded();
+#endif
 #endif
 
 #if PLATFORM(COCOA)
@@ -831,6 +835,7 @@ class WebProcessProxy final : public AuxiliaryProcessProxy {
 #endif
 #if ENABLE(MODEL_PROCESS)
     uint64_t m_sharedPreferencesVersionInModelProcess { 0 };
+    std::optional<String> m_memoryAttributionID;
 #endif
     uint64_t m_awaitedSharedPreferencesVersion { 0 };
     CompletionHandler<void(bool success)> m_sharedPreferencesForWebProcessCompletionHandler;
diff --git a/Source/WebKit/WebKitSwift/RealityKit/RKEntity.swift b/Source/WebKit/WebKitSwift/RealityKit/RKEntity.swift
index 27bacf27647a..1948972eb0ab 100644
--- a/Source/WebKit/WebKitSwift/RealityKit/RKEntity.swift
+++ b/Source/WebKit/WebKitSwift/RealityKit/RKEntity.swift
@@ -27,6 +27,7 @@ import Combine
 import CoreGraphics
 import Foundation
  @_spi(RealityKit) import RealityKit
+ @_spi(RealityKit_Webkit) import RealityKit
 import WebKitSwift
 import os
 import simd
@@ -52,11 +53,17 @@ public final class WKSRKEntity: NSObject {
 #endif
     }
 
-    @objc(loadFromData:completionHandler:) public static func load(from data: Data, completionHandler: @MainActor @escaping (WKSRKEntity?) -> Void) {
+    @objc(loadFromData:withAttributionTaskID:completionHandler:) public static func load(from data: Data, attributionTaskId: String?, completionHandler: @MainActor @escaping (WKSRKEntity?) -> Void) {
 #if canImport(RealityKit, _version: 377)
         Task {
             do {
-                let loadedEntity = try await Entity(fromData: data)
+                var loadOptions = Entity.__LoadOptions()
+#if canImport(RealityKit, _version: 400)
+                if let attributionTaskId {
+                    loadOptions.memoryAttributionID = attributionTaskId
+                }
+#endif
+                let loadedEntity = try await Entity(fromData: data, options: loadOptions)
                 let result: WKSRKEntity = .init(with: loadedEntity)
                 await completionHandler(result)
             } catch {
diff --git a/Source/WebKit/WebKitSwift/RealityKit/RealityKitBridging.h b/Source/WebKit/WebKitSwift/RealityKit/RealityKitBridging.h
index dbb331d1a0b3..02174c088627 100644
--- a/Source/WebKit/WebKitSwift/RealityKit/RealityKitBridging.h
+++ b/Source/WebKit/WebKitSwift/RealityKit/RealityKitBridging.h
@@ -61,7 +61,7 @@ typedef struct {
 @property (nonatomic) NSTimeInterval currentTime;
 
 + (bool)isLoadFromDataAvailable;
-+ (void)loadFromData:(NSData *)data completionHandler:(void (^)(WKSRKEntity * _Nullable entity))completionHandler;
++ (void)loadFromData:(NSData *)data withAttributionTaskID:(nullable NSString *)attributionTaskId completionHandler:(void (^)(WKSRKEntity * _Nullable entity))completionHandler;
 - (instancetype)initWithCoreEntity:(REEntityRef)coreEntity;
 - (void)setParentCoreEntity:(REEntityRef)parentCoreEntity preservingWorldTransform:(BOOL)preservingWorldTransform NS_SWIFT_NAME(setParent(_:preservingWorldTransform:));
 - (void)setUpAnimationWithAutoPlay:(BOOL)autoPlay;


Reviews:
user: login: mwyrzykowski
body: Thank you, previously discussed / commented offline and looks good, approving 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T01:37:09Z
user: login: achan00
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:14:09Z
user: login: achan00
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:14:37Z
user: login: achan00
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:21:23Z
user: login: achan00
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:22:12Z
user: login: amarchenko
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T19:32:09Z
user: login: achan00
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T20:08:51Z

Review comments:
diff_hunk: @@ -168,6 +168,33 @@
         completionHandler(IPC::SharedFileHandle::create(FileSystem::FileHandle::adopt([sharedSimulationConnection fileDescriptor])));
     });
 }
+
+#if HAVE(TASK_IDENTITY_TOKEN)
+void GPUProcess::createMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity, CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->createMemoryAttributionIDForTask(processIdentity.taskIdToken(), [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<NSString> attributionTaskID, RetainPtr<id> appService) mutable {
+        if (!attributionTaskID) {
+            RELEASE_LOG_ERROR(ModelElement, "GPUProcess: Memory attribution ID request failed");
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID request succeeded");
+        completionHandler(String(attributionTaskID.get()));
+    });
+}
+
+void GPUProcess::unregisterMemoryAttributionID(const String& attributionID, CompletionHandler<void()>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->unregisterMemoryAttributionID(attributionID, [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<id> appService) mutable {
+        if (appService.get() != nil)
path: Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
user: login: achan00
body: Nit: can just be `if (appService)`
created_at: 2025-04-11T16:14:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -168,6 +168,33 @@
         completionHandler(IPC::SharedFileHandle::create(FileSystem::FileHandle::adopt([sharedSimulationConnection fileDescriptor])));
     });
 }
+
+#if HAVE(TASK_IDENTITY_TOKEN)
+void GPUProcess::createMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity, CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->createMemoryAttributionIDForTask(processIdentity.taskIdToken(), [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<NSString> attributionTaskID, RetainPtr<id> appService) mutable {
+        if (!attributionTaskID) {
+            RELEASE_LOG_ERROR(ModelElement, "GPUProcess: Memory attribution ID request failed");
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID request succeeded");
+        completionHandler(String(attributionTaskID.get()));
+    });
+}
+
+void GPUProcess::unregisterMemoryAttributionID(const String& attributionID, CompletionHandler<void()>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->unregisterMemoryAttributionID(attributionID, [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<id> appService) mutable {
+        if (appService.get() != nil)
+            RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID unregistration succeeded");
path: Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
user: login: achan00
body: We should log an error if for some reason the unregistration failed.
created_at: 2025-04-11T16:14:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1217,6 +1217,44 @@ void WebProcessProxy::modelProcessExited(ProcessTerminationReason reason)
         page->modelProcessExited(reason);
 }
 
+#if HAVE(TASK_IDENTITY_TOKEN)
+void WebProcessProxy::createMemoryAttributionIDIfNeeded(CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    if (m_memoryAttributionID.has_value()) {
+        completionHandler(m_memoryAttributionID);
+        return;
+    }
+
+    RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because a web process is creating a memory attribution ID", this);
path: Source/WebKit/UIProcess/WebProcessProxy.cpp
user: login: achan00
body: We should remove this log because we are not actually taking a background assertion here.
created_at: 2025-04-11T16:21:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1217,6 +1217,44 @@ void WebProcessProxy::modelProcessExited(ProcessTerminationReason reason)
         page->modelProcessExited(reason);
 }
 
+#if HAVE(TASK_IDENTITY_TOKEN)
+void WebProcessProxy::createMemoryAttributionIDIfNeeded(CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    if (m_memoryAttributionID.has_value()) {
+        completionHandler(m_memoryAttributionID);
+        return;
+    }
+
+    RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because a web process is creating a memory attribution ID", this);
+    GPUProcessProxy::getOrCreate()->createMemoryAttributionIDForTask(m_processIdentity, [this, weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler)]
+    (const std::optional<String>& attributionTaskID) mutable {
+        if (!weakThis)
+            return;
+
+        if (attributionTaskID.has_value()) {
+            WEBPROCESSPROXY_RELEASE_LOG(Process, "createMemoryAttributionIDIfNeeded: created memory attribution ID");
+            m_memoryAttributionID = attributionTaskID;
+        }
+
+        completionHandler(m_memoryAttributionID);
+    });
+
+}
+
+void WebProcessProxy::unregisterMemoryAttributionIDIfNeeded()
+{
+    if (!m_memoryAttributionID.has_value())
+        return;
+
+    RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because a web process is unregistering memory attribution", this);
path: Source/WebKit/UIProcess/WebProcessProxy.cpp
user: login: achan00
body: Ditto.
created_at: 2025-04-11T16:22:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -168,6 +168,33 @@
         completionHandler(IPC::SharedFileHandle::create(FileSystem::FileHandle::adopt([sharedSimulationConnection fileDescriptor])));
     });
 }
+
+#if HAVE(TASK_IDENTITY_TOKEN)
+void GPUProcess::createMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity, CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->createMemoryAttributionIDForTask(processIdentity.taskIdToken(), [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<NSString> attributionTaskID, RetainPtr<id> appService) mutable {
+        if (!attributionTaskID) {
+            RELEASE_LOG_ERROR(ModelElement, "GPUProcess: Memory attribution ID request failed");
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID request succeeded");
+        completionHandler(String(attributionTaskID.get()));
+    });
+}
+
+void GPUProcess::unregisterMemoryAttributionID(const String& attributionID, CompletionHandler<void()>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->unregisterMemoryAttributionID(attributionID, [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<id> appService) mutable {
+        if (appService.get() != nil)
path: Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
user: login: amarchenko
body: Done.
created_at: 2025-04-11T19:18:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -168,6 +168,33 @@
         completionHandler(IPC::SharedFileHandle::create(FileSystem::FileHandle::adopt([sharedSimulationConnection fileDescriptor])));
     });
 }
+
+#if HAVE(TASK_IDENTITY_TOKEN)
+void GPUProcess::createMemoryAttributionIDForTask(WebCore::ProcessIdentity processIdentity, CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->createMemoryAttributionIDForTask(processIdentity.taskIdToken(), [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<NSString> attributionTaskID, RetainPtr<id> appService) mutable {
+        if (!attributionTaskID) {
+            RELEASE_LOG_ERROR(ModelElement, "GPUProcess: Memory attribution ID request failed");
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID request succeeded");
+        completionHandler(String(attributionTaskID.get()));
+    });
+}
+
+void GPUProcess::unregisterMemoryAttributionID(const String& attributionID, CompletionHandler<void()>&& completionHandler)
+{
+    Ref<WKSharedSimulationConnectionHelper> sharedSimulationConnectionHelper = adoptRef(*new WKSharedSimulationConnectionHelper);
+    sharedSimulationConnectionHelper->unregisterMemoryAttributionID(attributionID, [sharedSimulationConnectionHelper, completionHandler = WTFMove(completionHandler)] (RetainPtr<id> appService) mutable {
+        if (appService.get() != nil)
+            RELEASE_LOG(ModelElement, "GPUProcess: Memory attribution ID unregistration succeeded");
path: Source/WebKit/GPUProcess/cocoa/GPUProcessCocoa.mm
user: login: amarchenko
body: Done.
created_at: 2025-04-11T19:18:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1217,6 +1217,44 @@ void WebProcessProxy::modelProcessExited(ProcessTerminationReason reason)
         page->modelProcessExited(reason);
 }
 
+#if HAVE(TASK_IDENTITY_TOKEN)
+void WebProcessProxy::createMemoryAttributionIDIfNeeded(CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    if (m_memoryAttributionID.has_value()) {
+        completionHandler(m_memoryAttributionID);
+        return;
+    }
+
+    RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because a web process is creating a memory attribution ID", this);
path: Source/WebKit/UIProcess/WebProcessProxy.cpp
user: login: amarchenko
body: Done.
created_at: 2025-04-11T19:19:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1217,6 +1217,44 @@ void WebProcessProxy::modelProcessExited(ProcessTerminationReason reason)
         page->modelProcessExited(reason);
 }
 
+#if HAVE(TASK_IDENTITY_TOKEN)
+void WebProcessProxy::createMemoryAttributionIDIfNeeded(CompletionHandler<void(const std::optional<String>&)>&& completionHandler)
+{
+    if (m_memoryAttributionID.has_value()) {
+        completionHandler(m_memoryAttributionID);
+        return;
+    }
+
+    RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because a web process is creating a memory attribution ID", this);
+    GPUProcessProxy::getOrCreate()->createMemoryAttributionIDForTask(m_processIdentity, [this, weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler)]
+    (const std::optional<String>& attributionTaskID) mutable {
+        if (!weakThis)
+            return;
+
+        if (attributionTaskID.has_value()) {
+            WEBPROCESSPROXY_RELEASE_LOG(Process, "createMemoryAttributionIDIfNeeded: created memory attribution ID");
+            m_memoryAttributionID = attributionTaskID;
+        }
+
+        completionHandler(m_memoryAttributionID);
+    });
+
+}
+
+void WebProcessProxy::unregisterMemoryAttributionIDIfNeeded()
+{
+    if (!m_memoryAttributionID.has_value())
+        return;
+
+    RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because a web process is unregistering memory attribution", this);
path: Source/WebKit/UIProcess/WebProcessProxy.cpp
user: login: amarchenko
body: Done.
created_at: 2025-04-11T19:19:39Z
author_association: CONTRIBUTOR

PR comments:
user: login: webkit-early-warning-system
created_at: 2025-04-10T23:34:52Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/0da1c61709552577df9cd7704ce4aa707021d45b)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/99267 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/18914 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/9161 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/104396 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/49864 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/19203 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/27348 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/75551 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/32640 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/102274 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/14589 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/89625 "Passed tests") | [❌ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/55912 "Found 1 new API test failure: /WPE/TestSSL:/webkit/WebKitWebView/ephemeral-tls-errors (failure)") | 
| [✅ 🧪 webkitpy](https://ews-build.webkit.org/#/builders/6/builds/98740 "Passed tests") | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/14381 "Passed tests") | | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/49226 "Built successfully") | 
| | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/13/builds/84309 "Build was cancelled. Recent messages:OS: Sequoia (15.2), Xcode: 16.2; Running apply-patch; Checked out pull request; run-api-tests (cancelled)") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/7690 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/106753 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/26380 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/19227 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/84509 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/26743 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/85826 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/84025 "Passed tests") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/28686 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/6365 "Passed tests") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/20105 "The change is no longer eligible for processing.") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/26320 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/31511 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/26141 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/29454 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/27708 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-04-11T19:32:45Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/a75bfe72e4b75a6c5e796df65ef51860050f554c)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/99372 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/19021 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/9272 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/104503 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/49973 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/19310 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/27455 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/75631 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/32731 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/102379 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/14684 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/89719 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/55990 "Passed tests") | 
| [✅ 🧪 webkitpy](https://ews-build.webkit.org/#/builders/6/builds/98845 "Passed tests") | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/14478 "Passed tests") | | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/49333 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/84404 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/7788 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/106860 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/26486 "Built successfully") | [⏳ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/macOS-Sequoia-Debug-WK2-Tests-EWS "Waiting to run tests") | [❌ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/84590 "Found 1 new test failure: imported/w3c/web-platform-tests/css/css-view-transitions/active-view-transition-type-on-non-root.html (failure)") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/26848 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/85922 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/84103 "Passed tests") | 
| [❌ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/21337 "") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/28772 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/6463 "Passed tests") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/20229 "The change is no longer eligible for processing.") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/26426 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/31627 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/26246 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/29559 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/27813 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-commit-queue
created_at: 2025-04-11T23:12:45Z
body: No reviewer information in commit message, blocking PR #43928. Details: [Build #21337](https://ews-build.webkit.org/#/builders/19/builds/21337)
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-04-11T23:22:44Z
body: EWS run on current version of this PR (hash https://github.com/WebKit/WebKit/commit/8e7967fcf84f663c88f4c46327185c0b3432c503)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/99409 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/19059 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/9312 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/104540 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/50010 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/19347 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/27492 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/34/builds/75659 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/32753 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/102416 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/14714 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/89757 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/56018 "Passed tests") | 
| [✅ 🧪 webkitpy](https://ews-build.webkit.org/#/builders/6/builds/98882 "Passed tests") | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/14509 "Passed tests") | | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/49370 "Built successfully") | 
| | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/13/builds/84432 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | [  ~~🧪 mac-wk2~~](https://ews-build.webkit.org/#/builders/136/builds/7827 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/106898 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/26523 "Built successfully") | [  ~~🧪 mac-AS-debug-wk2~~](https://ews-build.webkit.org/#/builders/122/builds/19349 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/1/builds/84618 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/26885 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/85961 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/84132 "Passed tests") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/21339 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/28803 "Passed tests") | [  ~~🧪 mac-intel-wk2~~](https://ews-build.webkit.org/#/builders/137/builds/6499 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/20266 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/26463 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/31664 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/26283 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/29596 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/27850 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-commit-queue
created_at: 2025-04-12T00:18:00Z
body: Committed 293610@main (d1807b80b6c2): <https://commits.webkit.org/293610@main>

Reviewed commits have been landed. Closing PR #43928 and removing active labels.
author_association: COLLABORATOR