call method

Future<EngineCallResult> call(
  1. Pointer<Void> handle,
  2. String apiName,
  3. String id,
  4. String jsonParam,
)

异步调用。返回 Future 在 native 通过 send_port 投递响应时 complete。

机制(port-based,替代 per-call NativeCallable.listener):

  1. 首次调用惰性注册常驻 _callResponsePort(Dart_InitializeApiDL + AtomicEngine_RegisterSendPort + listen);
  2. 生成进程内唯一 token,把 completer 存入 _pendingCalls;
  3. 把 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;
}