call method
异步调用。返回 Future 在 native 通过 send_port 投递响应时 complete。
机制(port-based,替代 per-call NativeCallable.listener):
- 首次调用惰性注册常驻
_callResponsePort(Dart_InitializeApiDL+AtomicEngine_RegisterSendPort+listen); - 生成进程内唯一 token,把 completer 存入
_pendingCalls; - 把 token 随
AtomicEngine_Call传给 native,响应经 send_port 携带 token 回到_onCallResponse,按 token complete 并移除。
底层即便对同一 token 多次触发响应,第二次查表已无对应 completer,直接 忽略——从机制上消除一次性 trampoline 的 use-after-free。
Implementation
Future<EngineCallResult> call(
Pointer<Void> handle,
String apiName,
String id,
String jsonParam,
) {
final completer = Completer<EngineCallResult>();
if (handle == nullptr) {
// 与 C ABI 在 null handle 时的响应语义保持一致。
completer.complete(
const EngineCallResult(
code: -3, // kSdkNotInitialized
message: 'engine handle is null',
data: '',
),
);
return completer.future;
}
_ensureCallPortRegistered();
final token = _generateToken(apiName);
_pendingCalls[token] = completer;
final namePtr = apiName.toNativeUtf8();
final idPtr = id.toNativeUtf8();
final paramPtr = jsonParam.toNativeUtf8();
final tokenPtr = token.toNativeUtf8();
try {
_callFn(handle, namePtr, idPtr, paramPtr, tokenPtr);
} catch (e, st) {
// 同步抛异常(不应发生):撤销登记并兜底完成。
_pendingCalls.remove(token);
if (!completer.isCompleted) {
completer.completeError(e, st);
}
} finally {
calloc.free(namePtr);
calloc.free(idPtr);
calloc.free(paramPtr);
calloc.free(tokenPtr);
}
return completer.future;
}