Flutter中Drat虚拟机服务介绍 --- VmService

开篇

在Flutter有三种运行模式分别为release,debug,profile,在debug和profile模式下Flutter Engine会开启一个DartService Isolate,DartService Isolate会创建一个VmService。PS:在debug和profile模式是以JIT模式编译,而release模式是AOT模式编译。通过VM Service就可以获取到运行时的各种信息,DevTools也是基于此Service的可视化工具

Engine中创建VmService

非release模式下DartVM在启动的时候会多创建出DartService Isolate然后在DartService Isolate中启动Vm Service,DartService Isolate是一个独立的Isolate它与Mian Isolate之间的数据是隔离的,它们都有自己独立的Scope

1,Isolate的类型
  The root isolate forms a new isolate group. Child isolates are added to their parents groups. When the root isolate dies, all isolates in its group are terminated. Only root isolates get UI bindings. Root isolates execute their code on engine managed threads. All other isolates run their Dart code on Dart VM managed thread pool workers that the engine has no control over.

Isolate是Dart中类似线程的概念,详细的概念这里不做讲解了,简单的介绍一下Isolate的类型,每创建一个Flutter Engine就会创建出一个root Ioslate也就是Main Isolate,root Ioslate会关联到Engine创建的四个Runner中,如:IO操作会在IO Runner中执行,UI构建在UI Runner,渲染在GPU Runner中,与Platform通信在Platform Runner中,而普通的Ioslate会在Dart VM线程池中执行。

2,创建DartService Isolate

dart_isolate.cc

Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
    const char* package_root,
    const char* package_config,
    Dart_IsolateFlags* flags,
    char** error) {
 //...

// release 模式下会禁用
  if (!settings.enable_observatory) {
    return nullptr;
  }

  //在service_isolate中启动Vm Service
  tonic::DartState::Scope scope(service_isolate);
  if (!DartServiceIsolate::Startup(
          settings.observatory_host,           // server IP address
          settings.observatory_port,           // server observatory port
          tonic::DartState::HandleLibraryTag,  // embedder library tag handler
          false,  //  disable websocket origin check
          settings.disable_service_auth_codes,  // disable VM service auth codes
          settings.enable_service_port_fallback,  // enable fallback to port 0
                                                  // when bind fails.
          error                                   // error (out)
          )) {
    // Error is populated by call to startup.
    FML_DLOG(ERROR) << *error;
    return nullptr;
  }

//...
  return service_isolate->isolate();
}
2,启动Vm Service

dart_isolate.cc

bool DartServiceIsolate::Startup(std::string server_ip,
                                 intptr_t server_port,
                                 Dart_LibraryTagHandler embedder_tag_handler,
                                 bool disable_origin_check,
                                 bool disable_service_auth_codes,
                                 bool enable_service_port_fallback,
                                 char** error) {
  Dart_Isolate isolate = Dart_CurrentIsolate();

 //调用dart:vmservice_io中的代码
  Dart_Handle uri = Dart_NewStringFromCString("dart:vmservice_io");
  Dart_Handle library = Dart_LookupLibrary(uri);
  SHUTDOWN_ON_ERROR(library);
  Dart_Handle result = Dart_SetRootLibrary(library);
  SHUTDOWN_ON_ERROR(result);
  result = Dart_SetNativeResolver(library, GetNativeFunction, GetSymbol);
  SHUTDOWN_ON_ERROR(result);

  // Set the HTTP server's ip.
  result = Dart_SetField(library, Dart_NewStringFromCString("_ip"),
                         Dart_NewStringFromCString(server_ip.c_str()));

  return true;
}

上述代码的主要逻辑是调用vmservice_io库中的代码,该源码在/engine/src/third_party/dart/sdk/lib/_internal/vm/bin/vmservice_io.dart中

Server _lazyServerBoot() {
  var localServer = server;
  if (localServer != null) {
    return localServer;
  }
  // Lazily create service.
  final service = VMService();
  // Lazily create server.
  localServer = Server(service, _ip, _port, _originCheckDisabled,
      _authCodesDisabled, _serviceInfoFilename, _enableServicePortFallback);
  server = localServer;
  return localServer;
}

如何连接到VmService

Flutte中有一个封装好的库vm_service 可以使用,它的原理是通过websocket连接到Flutter Engine中的VM Service。在使用之前必须加上–disable-dds(dart developer service)参数禁用控制台的DevTools连接,因为该Service只允许一种连接请求

1,获取VM Service Uri

uri的配置具是在settings.h文件中,ip为本机地址127.0.0.1,端口号默认为0会选择一个空闲的端口

  // The IP address to which the Dart VM service is bound.
  std::string observatory_host;

  // The port to which the Dart VM service is bound. When set to `0`, a free
  // port will be automatically selected by the OS. A message is logged on the
  // target indicating the URL at which the VM service can be accessed.
  uint32_t observatory_port = 0;

在debug模式下可以通过FlutterJNI.java中的getObservatoryUri获取,observatoryUri这个静态字段是通过JNI在Native层赋值

  @Nullable
  /**
   * Observatory URI for the VM instance.
   *
   * 

Its value is set by the native engine once {@link #init(Context, String[], String, String, * String, long)} is run. */ public static String getObservatoryUri() { return observatoryUri; }

2,连接VmService

引入vm_service 库后通过如下代码连接到VmService

String url =  // 通过MethodChannel获取getObservatoryUri
Uri uri = Uri.parse(url);
Uri socketUri = convertToWebSocketUrl(serviceProtocolUrl: uri);
final vmService = await vmServiceConnectUri(socketUri.toString());

VmService它们之间的通信示意图如下:

Flutter中Drat虚拟机服务介绍 --- VmService_第1张图片

VmService的应用场景

VmService的实现基本都在engine/src/third_party/dart/runtime/vm/service.cc中,实现细节大家可以自行去查看,主要功能点包括内存,CPU,GC等性能信息,很多优秀的工具也是基于此开发的如:DevTools以及字节跳动开源的调试工具ume,它结合Expando的机制还可以拓展检测内存泄漏工具leak_detector

VmService中提供的服务

service.cc中动态注册了许多方法,service_methods_集合中都是VmService具备的能力

static const ServiceMethodDescriptor service_methods_[] = {
  { "_echo", Echo,
    NULL },
  { "_respondWithMalformedJson", RespondWithMalformedJson,
    NULL },
  { "_respondWithMalformedObject", RespondWithMalformedObject,
    NULL },
  { "_triggerEchoEvent", TriggerEchoEvent,
    NULL },
  { "addBreakpoint", AddBreakpoint,
    add_breakpoint_params },
  { "addBreakpointWithScriptUri", AddBreakpointWithScriptUri,
    add_breakpoint_with_script_uri_params },
  { "addBreakpointAtEntry", AddBreakpointAtEntry,
    add_breakpoint_at_entry_params },
  { "_addBreakpointAtActivation", AddBreakpointAtActivation,
    add_breakpoint_at_activation_params },
  { "_buildExpressionEvaluationScope", BuildExpressionEvaluationScope,
    build_expression_evaluation_scope_params },
  { "clearCpuSamples", ClearCpuSamples,
    clear_cpu_samples_params },
  { "clearVMTimeline", ClearVMTimeline,
    clear_vm_timeline_params, },
  { "_compileExpression", CompileExpression, compile_expression_params },
  { "_enableProfiler", EnableProfiler,
    enable_profiler_params, },
  { "evaluate", Evaluate,
    evaluate_params },
  { "evaluateInFrame", EvaluateInFrame,
    evaluate_in_frame_params },
  { "_getAllocationProfile", GetAllocationProfile,
    get_allocation_profile_params },
  { "getAllocationProfile", GetAllocationProfilePublic,
    get_allocation_profile_params },
  { "getAllocationTraces", GetAllocationTraces,
      get_allocation_traces_params },
  { "_getNativeAllocationSamples", GetNativeAllocationSamples,
      get_native_allocation_samples_params },
  { "getClassList", GetClassList,
    get_class_list_params },
  { "getCpuSamples", GetCpuSamples,
    get_cpu_samples_params },
  { "getFlagList", GetFlagList,
    get_flag_list_params },
  { "_getHeapMap", GetHeapMap,
    get_heap_map_params },
  { "getInboundReferences", GetInboundReferences,
    get_inbound_references_params },
  { "getInstances", GetInstances,
    get_instances_params },
  { "_getInstancesAsArray", GetInstancesAsArray,
    get_instances_as_array_params },
  { "getPorts", GetPorts,
    get_ports_params },
  { "getIsolate", GetIsolate,
    get_isolate_params },
  { "_getIsolateObjectStore", GetIsolateObjectStore,
    get_isolate_object_store_params },
  { "getIsolateGroup", GetIsolateGroup,
    get_isolate_group_params },
  { "getMemoryUsage", GetMemoryUsage,
    get_memory_usage_params },
  { "getIsolateGroupMemoryUsage", GetIsolateGroupMemoryUsage,
    get_isolate_group_memory_usage_params },
  { "_getIsolateMetric", GetIsolateMetric,
    get_isolate_metric_params },
  { "_getIsolateMetricList", GetIsolateMetricList,
    get_isolate_metric_list_params },
  { "getObject", GetObject,
    get_object_params },
  { "_getObjectStore", GetObjectStore,
    get_object_store_params },
  { "_getPersistentHandles", GetPersistentHandles,
      get_persistent_handles_params, },
  { "_getPorts", GetPortsPrivate,
    get_ports_private_params },
  { "getProcessMemoryUsage", GetProcessMemoryUsage,
    get_process_memory_usage_params },
  { "_getReachableSize", GetReachableSize,
    get_reachable_size_params },
  { "_getRetainedSize", GetRetainedSize,
    get_retained_size_params },
  { "getRetainingPath", GetRetainingPath,
    get_retaining_path_params },
  { "getScripts", GetScripts,
    get_scripts_params },
  { "getSourceReport", GetSourceReport,
    get_source_report_params },
  { "getStack", GetStack,
    get_stack_params },
  { "_getTagProfile", GetTagProfile,
    get_tag_profile_params },
  { "_getTypeArgumentsList", GetTypeArgumentsList,
    get_type_arguments_list_params },
  { "getVersion", GetVersion,
    get_version_params },
  { "getVM", GetVM,
    get_vm_params },
  { "getVMTimeline", GetVMTimeline,
    get_vm_timeline_params },
  { "getVMTimelineFlags", GetVMTimelineFlags,
    get_vm_timeline_flags_params },
  { "getVMTimelineMicros", GetVMTimelineMicros,
    get_vm_timeline_micros_params },
  { "invoke", Invoke, invoke_params },
  { "kill", Kill, kill_params },
  { "pause", Pause,
    pause_params },
  { "removeBreakpoint", RemoveBreakpoint,
    remove_breakpoint_params },
  { "reloadSources", ReloadSources,
    reload_sources_params },
  { "_reloadSources", ReloadSources,
    reload_sources_params },
  { "resume", Resume,
    resume_params },
  { "requestHeapSnapshot", RequestHeapSnapshot,
    request_heap_snapshot_params },
  { "_evaluateCompiledExpression", EvaluateCompiledExpression,
    evaluate_compiled_expression_params },
  { "setBreakpointState", SetBreakpointState,
    set_breakpoint_state_params },
  { "setExceptionPauseMode", SetExceptionPauseMode,
    set_exception_pause_mode_params },
  { "setFlag", SetFlag,
    set_flags_params },
  { "setLibraryDebuggable", SetLibraryDebuggable,
    set_library_debuggable_params },
  { "setName", SetName,
    set_name_params },
  { "setTraceClassAllocation", SetTraceClassAllocation,
    set_trace_class_allocation_params },
  { "setVMName", SetVMName,
    set_vm_name_params },
  { "setVMTimelineFlags", SetVMTimelineFlags,
    set_vm_timeline_flags_params },
  { "_collectAllGarbage", CollectAllGarbage,
    collect_all_garbage_params },
  { "_getDefaultClassesAliases", GetDefaultClassesAliases,
    get_default_classes_aliases_params },
};

总结

在阅读DartService Isolate的创建过程中我们发现DartService Isolate和Main Isolate之间的通信并不是基于SendPort而是使用的WebSocket 实现RPC远程通信,这样它在其它端也能进行访问(如:PC端浏览器打开)

你可能感兴趣的:(Flutter,flutter,android)