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.
   *
   * <p>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它们之间的通信示意图如下:

image-20220210204712515

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端浏览器打开)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 你可以使用 Flutter 的命令行工具清除 pub-cache。 在命令行/终端输入以下命令: ``` flutter pub cache repair ``` 这将清除 pub-cache 的所有内容,并重新下载所需的文件。 如果你想要更详细的控制,你可以手动删除 pub-cache 文件夹,它通常位于以下位置: - Windows:`%APPDATA%\Pub\Cache\bin` - Mac/Linux:`~/.pub-cache/bin` 然后在需要时,你可以在 Flutter 项目运行 `flutter pub get` 来重新下载需要的依赖项。 ### 回答2: 在Flutter,pub-cache是存储Flutter项目所需依赖包的地方。如果需要清除pub-cache的内容,可以按照以下步骤进行操作: 1. 打开命令行终端(Command Prompt)或终端(Terminal)。 2. 进入到Flutter SDK的安装目录,通常是在用户目录下的flutter文件夹。 3. 使用以下命令进入pub缓存目录:cd .pub-cache 4. 确保当前路径是在.pub-cache目录下。 5. 执行以下命令来清除pub-cache的内容:flutter pub cache clean 6. 稍等片刻,Flutter会清除pub-cache的内容。完成后,命令行会显示成功清除的提示信息。 需要注意的是,清除pub-cache的内容意味着清除所有已下载的依赖包。这样一来,在下次运行Flutter项目时,Flutter将会重新下载并构建所需的依赖包。因此,在清除pub-cache之前,请确保你了解清楚操作的后果,并确认需要清除pub-cache的内容。 此外,除了清除pub-cache的内容,还可以使用flutter pub cache list命令来查看当前pub-cache已安装的依赖包列表。这样可以帮助你进一步了解并管理当前项目所需的依赖包。 ### 回答3: 在Flutter,pub-cache是用于存储Flutter项目依赖的第三方库的位置。当我们使用pub命令安装依赖时,它们会被下载并存储在pub-cache目录。如果需要清除pub-cache的内容,可以按照以下步骤进行操作: 1. 首先,打开命令行界面并导航到当前Flutter项目的根目录。 2. 运行pub cache clean命令。这将清除pub-cache目录的所有内容,包括已下载的依赖。 3. 等待命令执行完成,此时pub-cache目录将被完全清除。 需要注意的是,清除pub-cache的内容会导致所有依赖被删除,因此在执行此操作之前,应确保不会影响到当前项目的运行和构建。 另外,如果只想清除特定依赖的缓存,可以使用pub cache remove命令。例如,运行pub cache remove package_name将删除名称为package_name的依赖缓存。这对于解决特定依赖问题时可能很有用。 总结:要清除pub-cache的所有内容,只需运行pub cache clean命令即可。此操作将删除项目所有依赖的缓存。如需清除特定依赖的缓存,可以使用pub cache remove命令,并指定要删除的依赖名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值