Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 672e587

Browse files
authored
Background Execution Implementation for iOS (#5539)
1 parent 500f91b commit 672e587

28 files changed

+700
-47
lines changed

analysis_options.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ linter:
4242
# - avoid_bool_literals_in_conditional_expressions # not yet tested
4343
# - avoid_catches_without_on_clauses # we do this commonly
4444
# - avoid_catching_errors # we do this commonly
45-
- avoid_classes_with_only_static_members
45+
- avoid_classes_with_only_static_members # We want to avoid classes that can be instantiated but only have statics
4646
- avoid_empty_else
4747
- avoid_function_literals_in_foreach_calls
4848
- avoid_init_to_null

lib/ui/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ source_set("ui") {
5252
"painting/shader.h",
5353
"painting/vertices.cc",
5454
"painting/vertices.h",
55+
"plugins/callback_cache.cc",
56+
"plugins/callback_cache.h",
5557
"semantics/semantics_node.cc",
5658
"semantics/semantics_node.h",
5759
"semantics/semantics_update.cc",

lib/ui/dart_runtime_hooks.cc

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <sstream>
1313

1414
#include "flutter/common/settings.h"
15+
#include "flutter/lib/ui/plugins/callback_cache.h"
1516
#include "flutter/lib/ui/ui_dart_state.h"
1617
#include "lib/fxl/build_config.h"
1718
#include "lib/fxl/logging.h"
@@ -36,6 +37,7 @@ extern void syslog(int, const char*, ...);
3637
}
3738
#endif
3839

40+
using tonic::DartConverter;
3941
using tonic::LogIfError;
4042
using tonic::ToDart;
4143

@@ -48,23 +50,25 @@ namespace blink {
4850
#define BUILTIN_NATIVE_LIST(V) \
4951
V(Logger_PrintString, 1) \
5052
V(SaveCompilationTrace, 0) \
51-
V(ScheduleMicrotask, 1)
53+
V(ScheduleMicrotask, 1) \
54+
V(GetCallbackHandle, 1) \
55+
V(GetCallbackFromHandle, 1)
5256

5357
BUILTIN_NATIVE_LIST(DECLARE_FUNCTION);
5458

5559
void DartRuntimeHooks::RegisterNatives(tonic::DartLibraryNatives* natives) {
5660
natives->Register({BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)});
5761
}
5862

59-
static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) {
63+
static Dart_Handle GetFunction(Dart_Handle builtin_library, const char* name) {
6064
Dart_Handle getter_name = ToDart(name);
6165
Dart_Handle closure = Dart_Invoke(builtin_library, getter_name, 0, nullptr);
6266
DART_CHECK_VALID(closure);
6367
return closure;
6468
}
6569

6670
static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate) {
67-
Dart_Handle print = GetClosure(builtin_library, "_getPrintClosure");
71+
Dart_Handle print = GetFunction(builtin_library, "_getPrintClosure");
6872

6973
Dart_Handle internal_library = Dart_LookupLibrary(ToDart("dart:_internal"));
7074

@@ -101,7 +105,7 @@ static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) {
101105
Dart_Handle schedule_microtask;
102106
if (is_ui_isolate) {
103107
schedule_microtask =
104-
GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
108+
GetFunction(builtin_library, "_getScheduleMicrotaskClosure");
105109
} else {
106110
Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
107111
Dart_Handle method_name =
@@ -125,7 +129,8 @@ static void InitDartIO(Dart_Handle builtin_library,
125129
DART_CHECK_VALID(Dart_SetField(platform_type, ToDart("_nativeScript"),
126130
ToDart(script_uri)));
127131
}
128-
Dart_Handle locale_closure = GetClosure(builtin_library, "_getLocaleClosure");
132+
Dart_Handle locale_closure =
133+
GetFunction(builtin_library, "_getLocaleClosure");
129134
DART_CHECK_VALID(
130135
Dart_SetField(platform_type, ToDart("_localeClosure"), locale_closure));
131136
}
@@ -223,4 +228,103 @@ void ScheduleMicrotask(Dart_NativeArguments args) {
223228
UIDartState::Current()->ScheduleMicrotask(closure);
224229
}
225230

231+
static std::string GetFunctionLibraryUrl(Dart_Handle closure) {
232+
if (Dart_IsClosure(closure)) {
233+
closure = Dart_ClosureFunction(closure);
234+
DART_CHECK_VALID(closure);
235+
}
236+
237+
if (!Dart_IsFunction(closure)) {
238+
return "";
239+
}
240+
241+
Dart_Handle url = Dart_Null();
242+
Dart_Handle owner = Dart_FunctionOwner(closure);
243+
if (Dart_IsInstance(owner)) {
244+
owner = Dart_ClassLibrary(owner);
245+
}
246+
if (Dart_IsLibrary(owner)) {
247+
url = Dart_LibraryUrl(owner);
248+
DART_CHECK_VALID(url);
249+
}
250+
return DartConverter<std::string>::FromDart(url);
251+
}
252+
253+
static std::string GetFunctionClassName(Dart_Handle closure) {
254+
Dart_Handle result;
255+
256+
if (Dart_IsClosure(closure)) {
257+
closure = Dart_ClosureFunction(closure);
258+
DART_CHECK_VALID(closure);
259+
}
260+
261+
if (!Dart_IsFunction(closure)) {
262+
return "";
263+
}
264+
265+
bool is_static = false;
266+
result = Dart_FunctionIsStatic(closure, &is_static);
267+
DART_CHECK_VALID(result);
268+
if (!is_static) {
269+
return "";
270+
}
271+
272+
result = Dart_FunctionOwner(closure);
273+
DART_CHECK_VALID(result);
274+
275+
if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) {
276+
return "";
277+
}
278+
return DartConverter<std::string>::FromDart(Dart_ClassName(result));
279+
}
280+
281+
static std::string GetFunctionName(Dart_Handle func) {
282+
DART_CHECK_VALID(func);
283+
284+
if (Dart_IsClosure(func)) {
285+
func = Dart_ClosureFunction(func);
286+
DART_CHECK_VALID(func);
287+
}
288+
289+
if (!Dart_IsFunction(func)) {
290+
return "";
291+
}
292+
293+
bool is_static = false;
294+
Dart_Handle result = Dart_FunctionIsStatic(func, &is_static);
295+
DART_CHECK_VALID(result);
296+
if (!is_static) {
297+
return "";
298+
}
299+
300+
result = Dart_FunctionName(func);
301+
if (Dart_IsError(result)) {
302+
Dart_PropagateError(result);
303+
return "";
304+
}
305+
306+
return DartConverter<std::string>::FromDart(result);
307+
}
308+
309+
void GetCallbackHandle(Dart_NativeArguments args) {
310+
Dart_Handle func = Dart_GetNativeArgument(args, 0);
311+
std::string name = GetFunctionName(func);
312+
std::string class_name = GetFunctionClassName(func);
313+
std::string library_path = GetFunctionLibraryUrl(func);
314+
315+
if (name.empty()) {
316+
Dart_SetReturnValue(args, Dart_Null());
317+
return;
318+
}
319+
Dart_SetReturnValue(
320+
args, DartConverter<int64_t>::ToDart(DartCallbackCache::GetCallbackHandle(
321+
name, class_name, library_path)));
322+
}
323+
324+
void GetCallbackFromHandle(Dart_NativeArguments args) {
325+
Dart_Handle h = Dart_GetNativeArgument(args, 0);
326+
int64_t handle = DartConverter<int64_t>::FromDart(h);
327+
Dart_SetReturnValue(args, DartCallbackCache::GetCallback(handle));
328+
}
329+
226330
} // namespace blink

lib/ui/dart_ui.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dart_ui_files = [
1111
"$flutter_root/lib/ui/lerp.dart",
1212
"$flutter_root/lib/ui/natives.dart",
1313
"$flutter_root/lib/ui/painting.dart",
14+
"$flutter_root/lib/ui/plugins.dart",
1415
"$flutter_root/lib/ui/pointer.dart",
1516
"$flutter_root/lib/ui/semantics.dart",
1617
"$flutter_root/lib/ui/text.dart",

lib/ui/natives.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ dynamic _saveCompilationTrace() native 'SaveCompilationTrace';
4848

4949
void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask';
5050

51+
int _getCallbackHandle(Function closure) native 'GetCallbackHandle';
52+
Function _getCallbackFromHandle(int handle) native 'GetCallbackFromHandle';
53+
5154
// Required for gen_snapshot to work correctly.
5255
int _isolateId;
5356

lib/ui/plugins.dart

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2018 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
part of dart.ui;
6+
7+
/// An wrapper for a raw callback handle.
8+
class CallbackHandle {
9+
final int _handle;
10+
11+
/// Create an instance using a raw callback handle.
12+
///
13+
/// Only values produced by a call to [CallbackHandle.toRawHandle] should be
14+
/// used, otherwise this object will be an invalid handle.
15+
CallbackHandle.fromRawHandle(this._handle)
16+
: assert(_handle != null, "'_handle' must not be null.");
17+
18+
/// Get the raw callback handle to pass over a [MethodChannel] or isolate
19+
/// port.
20+
int toRawHandle() => _handle;
21+
22+
@override
23+
int get hashCode => _handle;
24+
25+
@override
26+
bool operator ==(dynamic other) =>
27+
(other is CallbackHandle) && (_handle == other._handle);
28+
}
29+
30+
/// Functionality for Flutter plugin authors.
31+
abstract class PluginUtilities {
32+
// This class is only a namespace, and should not be instantiated or
33+
// extended directly.
34+
factory PluginUtilities._() => null;
35+
36+
static Map<Function, CallbackHandle> _forwardCache =
37+
<Function, CallbackHandle>{};
38+
static Map<CallbackHandle, Function> _backwardCache =
39+
<CallbackHandle, Function>{};
40+
41+
/// Get a handle to a named top-level or static callback function which can
42+
/// be easily passed between isolates.
43+
///
44+
/// `callback` must not be null.
45+
///
46+
/// Returns a [CallbackHandle] that can be provided to
47+
/// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the
48+
/// original callback. If `callback` is not a top-level or static function,
49+
/// null is returned.
50+
static CallbackHandle getCallbackHandle(Function callback) {
51+
assert(callback != null, "'callback' must not be null.");
52+
return _forwardCache.putIfAbsent(callback,
53+
() => new CallbackHandle.fromRawHandle(_getCallbackHandle(callback)));
54+
}
55+
56+
/// Get a tear-off of a named top-level or static callback represented by a
57+
/// handle.
58+
///
59+
/// `handle` must not be null.
60+
///
61+
/// If `handle` is not a valid handle returned by
62+
/// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a
63+
/// tear-off of the callback associated with `handle` is returned.
64+
static Function getCallbackFromHandle(CallbackHandle handle) {
65+
assert(handle != null, "'handle' must not be null.");
66+
return _backwardCache.putIfAbsent(
67+
handle, () => _getCallbackFromHandle(handle.toRawHandle()));
68+
}
69+
}

lib/ui/plugins/callback_cache.cc

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2018 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/lib/ui/plugins/callback_cache.h"
6+
#include "lib/fxl/logging.h"
7+
#include "lib/tonic/converter/dart_converter.h"
8+
9+
using tonic::ToDart;
10+
11+
namespace blink {
12+
13+
std::mutex DartCallbackCache::mutex_;
14+
std::map<int64_t, DartCallbackRepresentation> DartCallbackCache::cache_;
15+
16+
Dart_Handle DartCallbackCache::GetCallback(int64_t handle) {
17+
std::unique_lock<std::mutex> lock(mutex_);
18+
auto iterator = cache_.find(handle);
19+
if (iterator != cache_.end()) {
20+
DartCallbackRepresentation cb = iterator->second;
21+
return LookupDartClosure(cb.name, cb.class_name, cb.library_path);
22+
}
23+
return Dart_Null();
24+
}
25+
26+
int64_t DartCallbackCache::GetCallbackHandle(const std::string& name,
27+
const std::string& class_name,
28+
const std::string& library_path) {
29+
std::unique_lock<std::mutex> lock(mutex_);
30+
std::hash<std::string> hasher;
31+
int64_t hash = hasher(name);
32+
hash += hasher(class_name);
33+
hash += hasher(library_path);
34+
35+
if (cache_.find(hash) == cache_.end()) {
36+
cache_[hash] = {name, class_name, library_path};
37+
}
38+
return hash;
39+
}
40+
41+
std::unique_ptr<DartCallbackRepresentation>
42+
DartCallbackCache::GetCallbackInformation(int64_t handle) {
43+
std::unique_lock<std::mutex> lock(mutex_);
44+
auto iterator = cache_.find(handle);
45+
if (iterator != cache_.end()) {
46+
return std::make_unique<DartCallbackRepresentation>(iterator->second);
47+
}
48+
return nullptr;
49+
}
50+
51+
Dart_Handle DartCallbackCache::LookupDartClosure(
52+
const std::string& name,
53+
const std::string& class_name,
54+
const std::string& library_path) {
55+
Dart_Handle closure_name = ToDart(name);
56+
Dart_Handle library_name =
57+
library_path.empty() ? Dart_Null() : ToDart(library_path);
58+
Dart_Handle cls_name = class_name.empty() ? Dart_Null() : ToDart(class_name);
59+
DART_CHECK_VALID(closure_name);
60+
DART_CHECK_VALID(library_name);
61+
DART_CHECK_VALID(cls_name);
62+
63+
Dart_Handle library;
64+
if (library_name == Dart_Null()) {
65+
library = Dart_RootLibrary();
66+
} else {
67+
library = Dart_LookupLibrary(library_name);
68+
}
69+
DART_CHECK_VALID(library);
70+
71+
Dart_Handle closure;
72+
if (Dart_IsNull(cls_name)) {
73+
closure = Dart_GetClosure(library, closure_name);
74+
} else {
75+
Dart_Handle cls = Dart_GetClass(library, cls_name);
76+
DART_CHECK_VALID(cls);
77+
if (Dart_IsNull(cls)) {
78+
closure = Dart_Null();
79+
} else {
80+
closure = Dart_GetStaticMethodClosure(library, cls, closure_name);
81+
}
82+
}
83+
DART_CHECK_VALID(closure);
84+
return closure;
85+
}
86+
87+
} // namespace blink

0 commit comments

Comments
 (0)