-
Notifications
You must be signed in to change notification settings - Fork 814
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Backport a mojo WebUI fix for iOS (#23614)
- Loading branch information
Showing
2 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
diff --git a/ios/web/webui/mojo_facade.h b/ios/web/webui/mojo_facade.h | ||
index d563599628d61c32474407a0a58664f96b5f4d87..e2fb5cf157ceb7f4419b8d04c56d2471db7d1858 100644 | ||
--- a/ios/web/webui/mojo_facade.h | ||
+++ b/ios/web/webui/mojo_facade.h | ||
@@ -12,6 +12,7 @@ | ||
|
||
#include "base/functional/callback.h" | ||
#import "base/memory/raw_ptr.h" | ||
+#include "base/memory/weak_ptr.h" | ||
#include "base/values.h" | ||
#include "mojo/public/cpp/system/message_pipe.h" | ||
#include "mojo/public/cpp/system/simple_watcher.h" | ||
@@ -114,6 +115,16 @@ class MojoFacade { | ||
// returns that ID. The ID can be used by JS to reference this pipe. | ||
int AllocatePipeId(mojo::ScopedMessagePipeHandle pipe); | ||
|
||
+ // SimpleWatcher callback which notifies us when a handle's watched signals | ||
+ // are raised. `callback_id` identifies the JS-side callback registered for | ||
+ // this watcher, and `watch_id` identifies the JS-side MojoWatcher responsible | ||
+ // for the event. This ultimately invokes the JS-side callback and then | ||
+ // re-arms the watcher once the JS has run. | ||
+ void OnWatcherCallback(int callback_id, int watch_id, MojoResult result); | ||
+ | ||
+ // Calls ArmOrNotify() for matching watcher. | ||
+ void ArmOnNotifyWatcher(int watch_id); | ||
+ | ||
// Returns the pipe handle associated with `id` in JS, or an invalid handle if | ||
// no such association exists. | ||
mojo::MessagePipeHandle GetPipeFromId(int id); | ||
@@ -138,6 +149,8 @@ class MojoFacade { | ||
|
||
// Currently active watches created through this facade. | ||
std::map<int, std::unique_ptr<mojo::SimpleWatcher>> watchers_; | ||
+ | ||
+ base::WeakPtrFactory<MojoFacade> weak_ptr_factory_{this}; | ||
}; | ||
|
||
} // web |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm | ||
index a61282c6c8a98343dca39fc0e4d55cd03914e156..c256789b7f11332a845fad16281b13da88ad180b 100644 | ||
--- a/ios/web/webui/mojo_facade.mm | ||
+++ b/ios/web/webui/mojo_facade.mm | ||
@@ -4,6 +4,7 @@ | ||
|
||
#import "ios/web/webui/mojo_facade.h" | ||
|
||
+#import <Foundation/Foundation.h> | ||
#import <stdint.h> | ||
|
||
#import <limits> | ||
@@ -11,8 +12,6 @@ | ||
#import <utility> | ||
#import <vector> | ||
|
||
-#import <Foundation/Foundation.h> | ||
- | ||
#import "base/base64.h" | ||
#import "base/functional/bind.h" | ||
#import "base/ios/block_types.h" | ||
@@ -189,6 +188,43 @@ base::Value MojoFacade::HandleMojoHandleReadMessage(base::Value::Dict args) { | ||
return base::Value(std::move(result)); | ||
} | ||
|
||
+void MojoFacade::ArmOnNotifyWatcher(int watch_id) { | ||
+ auto watcher_it = watchers_.find(watch_id); | ||
+ if (watcher_it == watchers_.end()) { | ||
+ return; | ||
+ } | ||
+ watcher_it->second->ArmOrNotify(); | ||
+} | ||
+ | ||
+void MojoFacade::OnWatcherCallback(int callback_id, | ||
+ int watch_id, | ||
+ MojoResult result) { | ||
+ web::WebFrame* main_frame = | ||
+ web_state_->GetPageWorldWebFramesManager()->GetMainWebFrame(); | ||
+ if (!main_frame) { | ||
+ return; | ||
+ } | ||
+ | ||
+ NSString* script = | ||
+ [NSString stringWithFormat: | ||
+ @"Mojo.internal.watchCallbacksHolder.callCallback(%d, %d)", | ||
+ callback_id, result]; | ||
+ auto callback = base::BindOnce( | ||
+ [](base::WeakPtr<MojoFacade> facade, int watch_id, const base::Value*, | ||
+ NSError*) { | ||
+ if (facade) { | ||
+ facade->ArmOnNotifyWatcher(watch_id); | ||
+ } | ||
+ }, | ||
+ weak_ptr_factory_.GetWeakPtr(), watch_id); | ||
+ // The watcher will be rearmed in `callback` after `script` is executed. | ||
+ // `script` calls JS watcher callback which is expected to synchronously read | ||
+ // data from the handle (via readMessage). That way, the behavior matches C++ | ||
+ // mojo SimpleWatcher with ArmingPolicy::AUTOMATIC. | ||
+ main_frame->ExecuteJavaScript(base::SysNSStringToUTF16(script), | ||
+ std::move(callback)); | ||
+} | ||
+ | ||
base::Value MojoFacade::HandleMojoHandleWatch(base::Value::Dict args) { | ||
std::optional<int> pipe_id = args.FindInt("handle"); | ||
CHECK(pipe_id.has_value()); | ||
@@ -196,27 +232,21 @@ base::Value MojoFacade::HandleMojoHandleWatch(base::Value::Dict args) { | ||
CHECK(signals.has_value()); | ||
std::optional<int> callback_id = args.FindInt("callbackId"); | ||
CHECK(callback_id.has_value()); | ||
+ const int watch_id = ++last_watch_id_; | ||
+ | ||
+ // Note: base::Unretained() is safe because `this` owns all the watchers. | ||
+ auto callback = | ||
+ base::BindRepeating(&MojoFacade::OnWatcherCallback, | ||
+ base::Unretained(this), *callback_id, watch_id); | ||
|
||
- mojo::SimpleWatcher::ReadyCallback callback = base::BindRepeating( | ||
- ^(int inner_callback_id, MojoResult result) { | ||
- NSString* script = [NSString | ||
- stringWithFormat: | ||
- @"Mojo.internal.watchCallbacksHolder.callCallback(%d, %d)", | ||
- inner_callback_id, result]; | ||
- web::WebFrame* main_frame = | ||
- web_state_->GetPageWorldWebFramesManager()->GetMainWebFrame(); | ||
- if (main_frame) { | ||
- main_frame->ExecuteJavaScript(base::SysNSStringToUTF16(script)); | ||
- } | ||
- }, | ||
- *callback_id); | ||
auto watcher = std::make_unique<mojo::SimpleWatcher>( | ||
- FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC); | ||
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL); | ||
|
||
mojo::MessagePipeHandle pipe = GetPipeFromId(*pipe_id); | ||
watcher->Watch(pipe, *signals, callback); | ||
- watchers_.insert(std::make_pair(++last_watch_id_, std::move(watcher))); | ||
- return base::Value(last_watch_id_); | ||
+ watcher->ArmOrNotify(); | ||
+ watchers_.insert(std::make_pair(watch_id, std::move(watcher))); | ||
+ return base::Value(watch_id); | ||
} | ||
|
||
void MojoFacade::HandleMojoWatcherCancel(base::Value::Dict args) { |