<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh_cn"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://aimfly.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://aimfly.github.io/" rel="alternate" type="text/html" hreflang="zh_cn" /><updated>2025-05-18T12:33:54+00:00</updated><id>https://aimfly.github.io/feed.xml</id><title type="html">到不了的是远方，回不去的是故乡</title><entry><title type="html">perfetto源码解析-基础框架（3）</title><link href="https://aimfly.github.io/perfetto/performance/2025/04/22/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(3).html" rel="alternate" type="text/html" title="perfetto源码解析-基础框架（3）" /><published>2025-04-22T00:00:00+00:00</published><updated>2025-04-22T00:00:00+00:00</updated><id>https://aimfly.github.io/perfetto/performance/2025/04/22/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(3)</id><content type="html" xml:base="https://aimfly.github.io/perfetto/performance/2025/04/22/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(3).html"><![CDATA[<p>上篇介绍了traced运行流程和大体框架，本篇将分析producer的启动流程，以heapprofd为例</p>

<p>代码在src/profiling/memory</p>

<p>从main函数跟踪，很快就看到启动的主体部分。</p>
<pre><code class="language-cpp">int StartCentralHeapprofd() {
  // We set this up before launching any threads, so we do not have to use a
  // std::atomic for g_dump_evt.
  g_dump_evt = new base::EventFd();

  base::UnixTaskRunner task_runner;
  base::Watchdog::GetInstance()-&gt;Start();  // crash on exceedingly long tasks
  HeapprofdProducer producer(HeapprofdMode::kCentral, &amp;task_runner,
                             /* exit_when_done= */ false);

  int listening_raw_socket = GetListeningSocket();
  auto listening_socket = base::UnixSocket::Listen(
      base::ScopedFile(listening_raw_socket), &amp;producer.socket_delegate(),
      &amp;task_runner, base::SockFamily::kUnix, base::SockType::kStream);

  struct sigaction action = {};
  action.sa_handler = [](int) { g_dump_evt-&gt;Notify(); };
  // Allow to trigger a full dump by sending SIGUSR1 to heapprofd.
  // This will allow manually deciding when to dump on userdebug.
  PERFETTO_CHECK(sigaction(SIGUSR1, &amp;action, nullptr) == 0);
  task_runner.AddFileDescriptorWatch(g_dump_evt-&gt;fd(), [&amp;producer] {
    g_dump_evt-&gt;Clear();
    producer.DumpAll();
  });
  producer.ConnectWithRetries(GetProducerSocket());
  // TODO(fmayer): Create one producer that manages both heapprofd and Java
  // producers, so we do not have two connections to traced.
  JavaHprofProducer java_producer(&amp;task_runner);
  java_producer.ConnectWithRetries(GetProducerSocket());
  task_runner.Run();
  return 0;
}
</code></pre>
<!--more-->
<p>这一部分首先启了个Watchdog，这部分不详细解释了，</p>

<p>然后创建了HeapprofdProducer对象，接着监听了/dev/socket/heapprofd，base::UnixSocket::Listen上一篇已经提到过，这里不展开，只是要注意，监听socket后续的事件会由producer.socket_delegate()处理，这部分也在后面讨论。</p>

<p>接着注册了信号处理函数处理SIGUSR1，处理方法就是由task_runner去运行producer.DumpAll()</p>

<p>然后执行producer.ConnectWithRetries去连接/dev/socket/traced_producer</p>

<p>下面同样又创建了JavaHprofProducer并去连接/dev/socket/traced_producer</p>

<p>接着就进入了task_runner处理各种异步事件</p>

<p>看HeapprofdProducer::ConnectWithRetries，设置了状态，执行ConnectService</p>
<pre><code class="language-cpp">void HeapprofdProducer::ConnectWithRetries(const char* socket_name) {
  PERFETTO_DCHECK(state_ == kNotStarted);
  state_ = kNotConnected;

  ResetConnectionBackoff();
  producer_sock_name_ = socket_name;
  ConnectService();
}
</code></pre>
<p>再看ConnectService，这里能看到DataSource名称”android.heapprofd”</p>
<pre><code class="language-cpp">void HeapprofdProducer::ConnectService() {
  SetProducerEndpoint(ProducerIPCClient::Connect(
      producer_sock_name_, this, "android.heapprofd", task_runner_));
}
</code></pre>
<p>ProducerIPCClient::Connect里面直接创建ProducerIPCClientImpl对象，看它的构造函数，这里主要创建了Client的实例，然后调用了BindService。</p>
<pre><code class="language-cpp">ipc_channel_ =
    ipc::Client::CreateInstance(std::move(conn_args), task_runner);
ipc_channel_-&gt;BindService(producer_port_-&gt;GetWeakPtr());
</code></pre>
<p>先看CreateInstance，这里可以看到ClientImpl，还记得前面service使用的HostImpl吗，这里正是和它对应的Client实现</p>
<pre><code class="language-cpp">std::unique_ptr&lt;Client&gt; Client::CreateInstance(ConnArgs conn_args,
                                               base::TaskRunner* task_runner) {
  std::unique_ptr&lt;Client&gt; client(
      new ClientImpl(std::move(conn_args), task_runner));
  return client;
}
</code></pre>
<p>接着看ClientImpl的构造函数，这里用的else里的TryConnect，而TryConnect调用了UnixSocket::Connect，注意这里的第二个参数this是EventListener，即ClientImpl处理socket事件的回调。</p>
<pre><code class="language-cpp">ClientImpl::ClientImpl(ConnArgs conn_args, base::TaskRunner* task_runner)
    : socket_name_(conn_args.socket_name),
      socket_retry_(conn_args.retry),
      task_runner_(task_runner),
      weak_ptr_factory_(this) {
  if (conn_args.socket_fd) {
    // Create the client using a connected socket. This code path will never hit
    // OnConnect().
    sock_ = base::UnixSocket::AdoptConnected(
        std::move(conn_args.socket_fd), this, task_runner_, kClientSockFamily,
        base::SockType::kStream, base::SockPeerCredMode::kIgnore);
  } else {
    // Connect using the socket name.
    TryConnect();
  }
}

void ClientImpl::TryConnect() {
  PERFETTO_DCHECK(socket_name_);
  sock_ = base::UnixSocket::Connect(
      socket_name_, this, task_runner_, base::GetSockFamily(socket_name_),
      base::SockType::kStream, base::SockPeerCredMode::kIgnore);
}
</code></pre>
<p>UnixSocket::Connect里首先创建了UnixSocket对象，然后调用了它的DoConnect</p>

<p>先看UnixSocket的构造函数，这里adopt_state传进来是kDisconnected，所以会创建一个socket,设为非阻塞，并且把它添加到task_runner_的监听列表中，还记得service socket这里做的是什么吗？前面提到service里adopt_state传进来是kListening。</p>
<pre><code class="language-cpp">  state_ = State::kDisconnected;
  if (adopt_state == State::kDisconnected) {
    PERFETTO_DCHECK(!adopt_fd);
    sock_raw_ = UnixSocketRaw::CreateMayFail(sock_family, sock_type);
    if (!sock_raw_)
      return;
  } else if (adopt_state == State::kConnected) {
...
  PERFETTO_CHECK(sock_raw_);
  sock_raw_.SetBlocking(false);
  WeakPtr&lt;UnixSocket&gt; weak_ptr = weak_ptr_factory_.GetWeakPtr();
  task_runner_-&gt;AddFileDescriptorWatch(sock_raw_.watch_handle(), [weak_ptr] {
    if (weak_ptr)
      weak_ptr-&gt;OnEvent();
  });
</code></pre>
<p>上面的构造函数并没有连接service,这部分在DoConnect里做了，并且把state_从kDisconnected切换到了kConnecting，这里有一大段注释省略了，大概意思是解释了下面为什么要在task_runner_里执行一次OnEvent，OnEvent是socket状态有变化时的直接回调。</p>
<pre><code class="language-cpp">void UnixSocket::DoConnect(const std::string&amp; socket_name) {
  PERFETTO_DCHECK(state_ == State::kDisconnected);

  // This is the only thing that can gracefully fail in the ctor.
  if (!sock_raw_)
    return NotifyConnectionState(false);

  if (!sock_raw_.Connect(socket_name))
    return NotifyConnectionState(false);

  // At this point either connect() succeeded or started asynchronously
  // (errno = EINPROGRESS).
  state_ = State::kConnecting;
...
  WeakPtr&lt;UnixSocket&gt; weak_ptr = weak_ptr_factory_.GetWeakPtr();
  task_runner_-&gt;PostTask([weak_ptr] {
    if (weak_ptr)
      weak_ptr-&gt;OnEvent();
  });
}
</code></pre>
<p>至此socket初始化和连接部分结束了，回到ProducerIPCClient::Connect那里，接着调用了ClientImpl::BindService，还记得前面socket的状态是什么吗？</p>

<p>是kConnecting，所以这里也就是把service_proxy添加到queued_bindings_等后续做处理</p>
<pre><code class="language-cpp">void ClientImpl::BindService(base::WeakPtr&lt;ServiceProxy&gt; service_proxy) {
  if (!service_proxy)
    return;
  if (!sock_-&gt;is_connected()) {
    queued_bindings_.emplace_back(service_proxy);
    return;
  }
  ...
}
</code></pre>
<p>这个service_proxy是什么呢，它的类型是protos::gen::ProducerPortProxy，也是protobuf自动生产</p>

<p>它是ProducerIPCClientImpl初始化时创建的用于和service收发消息的代理对象，并且看到这个对象接受了ProducerIPCClientImpl对象做为回调事件的处理</p>
<pre><code class="language-cpp">      producer_port_(
          new protos::gen::ProducerPortProxy(this /* event_listener */)),
</code></pre>
<p>这之后就会进入task_runner来处理各种异步事件，这里总结一下各个类的关系方便下面继续分析。</p>

<p>最外层的是HeapprofdProducer对象，它包含了对heap profiler的一些业务流的处理，这部分会在其他章节说明。</p>

<p>接下来是ProducerIPCClientImpl对象处理producer客户端相关的业务。它又是protos::gen::ProducerPortProxy的事件监听者。</p>

<p>然后是ClientImpl处理客户端业务。它会使用ProducerPortProxy来和服务端通信。</p>

<p>最后是UnixSocket处理socket事件。</p>

<p>刚才提到socket连接后进入了kConnecting状态，然后task_runner紧接着会回调UnixSocket::OnEvent</p>

<p>来看它的处理，这里正常会执行回调event_listener_-&gt;OnConnect(this, true /* connected */)，而event_listener_就是ClientImpl</p>
<pre><code class="language-cpp">  if (state_ == State::kConnecting) {
    PERFETTO_DCHECK(sock_raw_);
    int sock_err = EINVAL;
    socklen_t err_len = sizeof(sock_err);
    int res =
        getsockopt(sock_raw_.fd(), SOL_SOCKET, SO_ERROR, &amp;sock_err, &amp;err_len);

    if (res == 0 &amp;&amp; sock_err == EINPROGRESS)
      return;  // Not connected yet, just a spurious FD watch wakeup.
    if (res == 0 &amp;&amp; sock_err == 0) {
      if (peer_cred_mode_ == SockPeerCredMode::kReadOnConnect)
        ReadPeerCredentialsPosix();
      state_ = State::kConnected;
      return event_listener_-&gt;OnConnect(this, true /* connected */);
    }
    PERFETTO_DLOG("Connection error: %s", strerror(sock_err));
    Shutdown(false);
    return event_listener_-&gt;OnConnect(this, false /* connected */);
  }
</code></pre>
<p>看ClientImpl::OnConnect，这里又执行了BindService</p>
<pre><code class="language-cpp">  auto queued_bindings = std::move(queued_bindings_);
  queued_bindings_.clear();
  for (base::WeakPtr&lt;ServiceProxy&gt;&amp; service_proxy : queued_bindings) {
    if (connected) {
      BindService(service_proxy);
    } else if (service_proxy) {
      service_proxy-&gt;OnConnect(false /* success */);
    }
  }
</code></pre>
<p>接着看BindService另一部分，这里看到组装了带有bind_service消息的protos::gen::IPCFrame并且调用了SendFrame发送，然后把request放进了queued_requests_</p>
<pre><code class="language-cpp">  RequestID request_id = ++last_request_id_;
  Frame frame;
  frame.set_request_id(request_id);
  Frame::BindService* req = frame.mutable_msg_bind_service();
  const char* const service_name = service_proxy-&gt;GetDescriptor().service_name;
  req-&gt;set_service_name(service_name);
  if (!SendFrame(frame)) {
    PERFETTO_DLOG("BindService(%s) failed", service_name);
    return service_proxy-&gt;OnConnect(false /* success */);
  }
  QueuedRequest qr;
  qr.type = Frame::kMsgBindServiceFieldNumber;
  qr.request_id = request_id;
  qr.service_proxy = service_proxy;
  queued_requests_.emplace(request_id, std::move(qr));
</code></pre>
<p>SendFrame下面就是做了序列化和发送，不细说了，然后看server端处理，也就是traced。</p>

<p>前面章节也提到过服务端收到数据会调用UnixSocket::OnEvent，然后调用它事件监听者即HostImpl的OnDataAvailable，然后调用OnReceivedFrame。</p>

<p>HostImpl::OnReceivedFrame比较简单，它这里会调用OnBindService，这里直接组装msg_bind_service_reply回复，回复中带了service id和method ids。</p>
<pre><code class="language-cpp">void HostImpl::OnBindService(ClientConnection* client, const Frame&amp; req_frame) {
  // Binding a service doesn't do anything major. It just returns back the
  // service id and its method map.
  const Frame::BindService&amp; req = req_frame.msg_bind_service();
  Frame reply_frame;
  reply_frame.set_request_id(req_frame.request_id());
  auto* reply = reply_frame.mutable_msg_bind_service_reply();
  const ExposedService* service = GetServiceByName(req.service_name());
  if (service) {
    reply-&gt;set_success(true);
    reply-&gt;set_service_id(service-&gt;id);
    uint32_t method_id = 1;  // method ids start at index 1.
    for (const auto&amp; desc_method : service-&gt;instance-&gt;GetDescriptor().methods) {
      Frame::BindServiceReply::MethodInfo* method_info = reply-&gt;add_methods();
      method_info-&gt;set_name(desc_method.name);
      method_info-&gt;set_id(method_id++);
    }
  }
  SendFrame(client, reply_frame);
}
</code></pre>
<p>接着看客户端的处理，还记得之前发请求时存过queued_requests_，这里先拿到reply对应的request，接着用request和reply调用了OnBindServiceReply</p>
<pre><code class="language-cpp">void ClientImpl::OnFrameReceived(const Frame&amp; frame) {
  auto queued_requests_it = queued_requests_.find(frame.request_id());
  if (queued_requests_it == queued_requests_.end()) {
    PERFETTO_DLOG("OnFrameReceived(): got invalid request_id=%" PRIu64,
                  static_cast&lt;uint64_t&gt;(frame.request_id()));
    return;
  }
  QueuedRequest req = std::move(queued_requests_it-&gt;second);
  queued_requests_.erase(queued_requests_it);

  if (req.type == Frame::kMsgBindServiceFieldNumber &amp;&amp;
      frame.has_msg_bind_service_reply()) {
    return OnBindServiceReply(std::move(req), frame.msg_bind_service_reply());
  }
  if (req.type == Frame::kMsgInvokeMethodFieldNumber &amp;&amp;
      frame.has_msg_invoke_method_reply()) {
    return OnInvokeMethodReply(std::move(req), frame.msg_invoke_method_reply());
  }
...
}
</code></pre>
<p>接着看OnBindServiceReply，这里主要就是用服务端发回的service id和method ids初始化service_proxy，即ProducerPortProxy，目的是请求服务端执行某方法时，确保方法存在。同时存入service_bindings_</p>
<pre><code class="language-cpp">void ClientImpl::OnBindServiceReply(QueuedRequest req,
                                    const Frame::BindServiceReply&amp; reply) {
  base::WeakPtr&lt;ServiceProxy&gt;&amp; service_proxy = req.service_proxy;
  if (!service_proxy)
    return;
  const char* svc_name = service_proxy-&gt;GetDescriptor().service_name;
  if (!reply.success()) {
    PERFETTO_DLOG("BindService(): unknown service_name=\"%s\"", svc_name);
    return service_proxy-&gt;OnConnect(false /* success */);
  }

  auto prev_service = service_bindings_.find(reply.service_id());
  if (prev_service != service_bindings_.end() &amp;&amp; prev_service-&gt;second.get()) {
    PERFETTO_DLOG(
        "BindService(): Trying to bind service \"%s\" but another service "
        "named \"%s\" is already bound with the same ID.",
        svc_name, prev_service-&gt;second-&gt;GetDescriptor().service_name);
    return service_proxy-&gt;OnConnect(false /* success */);
  }

  // Build the method [name] -&gt; [remote_id] map.
  std::map&lt;std::string, MethodID&gt; methods;
  for (const auto&amp; method : reply.methods()) {
    if (method.name().empty() || method.id() &lt;= 0) {
      PERFETTO_DLOG("OnBindServiceReply(): invalid method \"%s\" -&gt; %" PRIu64,
                    method.name().c_str(), static_cast&lt;uint64_t&gt;(method.id()));
      continue;
    }
    methods[method.name()] = method.id();
  }
  service_proxy-&gt;InitializeBinding(weak_ptr_factory_.GetWeakPtr(),
                                   reply.service_id(), std::move(methods));
  service_bindings_[reply.service_id()] = service_proxy;
  service_proxy-&gt;OnConnect(true /* success */);
}
</code></pre>
<p>接着看service_proxy-&gt;OnConnect，ProducerPortProxy继承了ServiceProxy，所以这段代码在ServiceProxy里</p>

<p>还记得这里事件监听者是什么么，没错，是ProducerIPCClientImpl</p>
<pre><code class="language-cpp">void ServiceProxy::OnConnect(bool success) {
  if (success) {
    PERFETTO_DCHECK(service_id_);
    return event_listener_-&gt;OnConnect();
  }
  return event_listener_-&gt;OnDisconnect();
}
</code></pre>
<p>来看ProducerIPCClientImpl::OnConnect，这里主要做了两件事，一是调用了ProducerPortProxy的InitializeConnection，
二是调用了GetAsyncCommand，并且分别注册了回调，GetAsyncCommand非常重要，它告诉服务端已经准备好接受后续命令，并且在回调中处理后续命令，例如SetupDataSource，StartTracing等。</p>
<pre><code class="language-cpp">void ProducerIPCClientImpl::OnConnect() {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  connected_ = true;

  ipc::Deferred&lt;protos::gen::InitializeConnectionResponse&gt; on_init;
  on_init.Bind(
      [this](ipc::AsyncResult&lt;protos::gen::InitializeConnectionResponse&gt; resp) {
        OnConnectionInitialized(
            resp.success(),
            resp.success() ? resp-&gt;using_shmem_provided_by_producer() : false,
            resp.success() ? resp-&gt;direct_smb_patching_supported() : false,
            resp.success() ? resp-&gt;use_shmem_emulation() : false);
      });
  protos::gen::InitializeConnectionRequest req;
  req.set_producer_name(name_);
  req.set_shared_memory_size_hint_bytes(
      static_cast&lt;uint32_t&gt;(shared_memory_size_hint_bytes_));
  req.set_shared_memory_page_size_hint_bytes(
      static_cast&lt;uint32_t&gt;(shared_memory_page_size_hint_bytes_));
  ...

  req.set_sdk_version(base::GetVersionString());
  producer_port_-&gt;InitializeConnection(req, std::move(on_init), shm_fd);

  // Create the back channel to receive commands from the Service.
  ipc::Deferred&lt;protos::gen::GetAsyncCommandResponse&gt; on_cmd;
  on_cmd.Bind(
      [this](ipc::AsyncResult&lt;protos::gen::GetAsyncCommandResponse&gt; resp) {
        if (!resp)
          return;  // The IPC channel was closed and |resp| was auto-rejected.
        OnServiceRequest(*resp);
      });
  producer_port_-&gt;GetAsyncCommand(protos::gen::GetAsyncCommandRequest(),
                                  std::move(on_cmd));

  // If there are pending Sync() requests, send them now.
  for (const auto&amp; pending_sync : pending_sync_reqs_)
    Sync(std::move(pending_sync));
  pending_sync_reqs_.clear();
}
</code></pre>
<p>接着看生成的ProducerPortProxy::InitializeConnection是如何实现的，这段代码在out/soong/.intermediates/external/perfetto/perfetto_protos_perfetto_ipc_ipc_gen/gen/external/perfetto/protos/perfetto/ipc/producer_port.ipc.cc，它调用了BeginInvoke，实现在ServiceProxy里，前面提到过ProducerPortProxy继承于ServiceProxy</p>
<pre><code class="language-cpp">void ProducerPortProxy::InitializeConnection(const InitializeConnectionRequest&amp; request, DeferredInitializeConnectionResponse reply, int fd) {
  BeginInvoke("InitializeConnection", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
              fd);
}
</code></pre>
<p>可以看到这里首先看需要执行的方法service端是否支持，也就是前面BindService返回的，可以认为这种做法是为了后续的扩展。</p>

<p>紧接着调用了ClientImpl的BeginInvoke，并且把收到回复的回调放进pending_callbacks_，上面InitializeConnection的回调就是ProducerIPCClientImpl::OnConnectionInitialized</p>
<pre><code class="language-cpp">void ServiceProxy::BeginInvoke(const std::string&amp; method_name,
                               const ProtoMessage&amp; request,
                               DeferredBase reply,
                               int fd) {
...
  auto remote_method_it = remote_method_ids_.find(method_name);
  RequestID request_id = 0;
  const bool drop_reply = !reply.IsBound();
  if (remote_method_it != remote_method_ids_.end()) {
    request_id =
        static_cast&lt;ClientImpl*&gt;(client_.get())
            -&gt;BeginInvoke(service_id_, method_name, remote_method_it-&gt;second,
                          request, drop_reply, weak_ptr_factory_.GetWeakPtr(),
                          fd);
  } else {
    PERFETTO_DLOG("Cannot find method \"%s\" on the host", method_name.c_str());
  }
...
  pending_callbacks_.emplace(request_id, std::move(reply));
}
</code></pre>
<p>接着看ClientImpl::BeginInvoke，主要做了两件事，一是发送IPCFrame带invoke_method消息,一是将请求暂存到queued_requests_，queued_requests_的用处在BindService那里已经说过，后面就不展开了</p>
<pre><code class="language-cpp">RequestID ClientImpl::BeginInvoke(ServiceID service_id,
                                  const std::string&amp; method_name,
                                  MethodID remote_method_id,
                                  const ProtoMessage&amp; method_args,
                                  bool drop_reply,
                                  base::WeakPtr&lt;ServiceProxy&gt; service_proxy,
                                  int fd) {
  RequestID request_id = ++last_request_id_;
  Frame frame;
  frame.set_request_id(request_id);
  Frame::InvokeMethod* req = frame.mutable_msg_invoke_method();
...
  if (!SendFrame(frame, fd)) {
    PERFETTO_DLOG("BeginInvoke() failed while sending the frame");
    return 0;
  }
  if (drop_reply)
    return 0;
  QueuedRequest qr;
...
  queued_requests_.emplace(request_id, std::move(qr));
  return request_id;
}
</code></pre>
<p>接下来看Server端的处理，从UnixSocket::OnEvent再到HostImpl::OnDataAvailable再到HostImpl::OnReceivedFrame前面有过分析</p>

<p>接着会调用到HostImpl::OnInvokeMethod，这个里面首先会检查请求发来service和method是否存在，接着取出method回调，还记得这是在哪里初始化的吗，在生成的producer_port.ipc.cc里</p>

<p>然后构造了延时回复消息的回调，接着在构造当前请求ClientInfo赋给service，这个地方的service是之前ExposeService生成的，然后调用method.invoker</p>
<pre><code class="language-cpp">void HostImpl::OnInvokeMethod(ClientConnection* client,
                              const Frame&amp; req_frame) {
  const Frame::InvokeMethod&amp; req = req_frame.msg_invoke_method();
  Frame reply_frame;
  RequestID request_id = req_frame.request_id();
  reply_frame.set_request_id(request_id);
  reply_frame.mutable_msg_invoke_method_reply()-&gt;set_success(false);
  auto svc_it = services_.find(req.service_id());
  if (svc_it == services_.end())
    return SendFrame(client, reply_frame);  // |success| == false by default.

  Service* service = svc_it-&gt;second.instance.get();
  const ServiceDescriptor&amp; svc = service-&gt;GetDescriptor();
  const auto&amp; methods = svc.methods;
  const uint32_t method_id = req.method_id();
  if (method_id == 0 || method_id &gt; methods.size())
    return SendFrame(client, reply_frame);

  const ServiceDescriptor::Method&amp; method = methods[method_id - 1];
  std::unique_ptr&lt;ProtoMessage&gt; decoded_req_args(
      method.request_proto_decoder(req.args_proto()));
  if (!decoded_req_args)
    return SendFrame(client, reply_frame);

  Deferred&lt;ProtoMessage&gt; deferred_reply;
  base::WeakPtr&lt;HostImpl&gt; host_weak_ptr = weak_ptr_factory_.GetWeakPtr();
  ClientID client_id = client-&gt;id;

  if (!req.drop_reply()) {
    deferred_reply.Bind([host_weak_ptr, client_id,
                         request_id](AsyncResult&lt;ProtoMessage&gt; reply) {
      if (!host_weak_ptr)
        return;  // The reply came too late, the HostImpl has gone.
      host_weak_ptr-&gt;ReplyToMethodInvocation(client_id, request_id,
                                             std::move(reply));
    });
  }

  auto peer_uid = client-&gt;GetPosixPeerUid();
  auto scoped_key = g_crash_key_uid.SetScoped(static_cast&lt;int64_t&gt;(peer_uid));
  service-&gt;client_info_ = ClientInfo(
      client-&gt;id, peer_uid, client-&gt;GetLinuxPeerPid(), client-&gt;GetMachineID());
  service-&gt;received_fd_ = &amp;client-&gt;received_fd;
  method.invoker(service, *decoded_req_args, std::move(deferred_reply));
  service-&gt;received_fd_ = nullptr;
  service-&gt;client_info_ = ClientInfo();
}
</code></pre>
<p>前面提到过method.invoker对应的例如是这个 &amp;_IPC_Invoker&lt;ProducerPort, InitializeConnectionRequest, InitializeConnectionResponse, &amp;ProducerPort::InitializeConnection&gt;，ProducerPort::InitializeConnection对应的正是ProducerIPCService::InitializeConnection</p>

<p>这里先取出之前暂存的client_info，细心的会发现这里不是多线程可重入的，因为每次请求来，client_info都会更新，当然这些异步事件都是在task_runner的工作线程中执行，并没有多线程问题。</p>

<p>这里先判断producer有没有注册过，然后会注册一个新的RemoteProducer放进producers_中，这里会调用core_service_-&gt;ConnectProducer，core_service_即为TracingService也是负责tracing业务的核心对象。最后通过response.Resolve来调用回复消息的回调，再看上一段，回调为host_weak_ptr-&gt;ReplyToMethodInvocation</p>
<pre><code class="language-cpp">void ProducerIPCService::InitializeConnection(
    const protos::gen::InitializeConnectionRequest&amp; req,
    DeferredInitializeConnectionResponse response) {
  const auto&amp; client_info = ipc::Service::client_info();
  const ipc::ClientID ipc_client_id = client_info.client_id();
  PERFETTO_CHECK(ipc_client_id);

  if (producers_.count(ipc_client_id) &gt; 0) {
    PERFETTO_DLOG(
        "The remote Producer is trying to re-initialize the connection");
    return response.Reject();
  }

  // Create a new entry.
  std::unique_ptr&lt;RemoteProducer&gt; producer(new RemoteProducer());
...
  // Copy the data fields to be emitted to trace packets into ClientIdentity.
  ClientIdentity client_identity(client_info.uid(), client_info.pid(),
                                 client_info.machine_id());
  // ConnectProducer will call OnConnect() on the next task.
  producer-&gt;service_endpoint = core_service_-&gt;ConnectProducer(
      producer.get(), client_identity, req.producer_name(),
      req.shared_memory_size_hint_bytes(),
      /*in_process=*/false, smb_scraping_mode,
      req.shared_memory_page_size_hint_bytes(), std::move(shmem),
      req.sdk_version());
...

  producers_.emplace(ipc_client_id, std::move(producer));
  // Because of the std::move() |producer| is invalid after this point.

  auto async_res =
      ipc::AsyncResult&lt;protos::gen::InitializeConnectionResponse&gt;::Create();
  async_res-&gt;set_using_shmem_provided_by_producer(using_producer_shmem);
  async_res-&gt;set_direct_smb_patching_supported(true);
  async_res-&gt;set_use_shmem_emulation(use_shmem_emulation);
  response.Resolve(std::move(async_res));
}
</code></pre>
<p>先看ConnectProducer做了什么，创建了ProducerEndpointImpl对象放进producers_，并且将它的OnConnect放进task_runner的执行列表，再返回ProducerEndpointImpl对象，ProducerIPCService里将这个对象赋给了RemoteProducer的service_endpoint，这里和上层都有producers_，容易看晕，来理一下，TracingServiceImpl因为和tracing业务有关，所以自然想到ProducerEndpointImpl是和tracing业务相关的，然后上层的RemoteProducer会想到是和IPC相关的。后面再看是不是。</p>
<pre><code class="language-cpp">std::unique_ptr&lt;TracingService::ProducerEndpoint&gt;
TracingServiceImpl::ConnectProducer(Producer* producer,
                                    const ClientIdentity&amp; client_identity,
                                    const std::string&amp; producer_name,
                                    size_t shared_memory_size_hint_bytes,
                                    bool in_process,
                                    ProducerSMBScrapingMode smb_scraping_mode,
                                    size_t shared_memory_page_size_hint_bytes,
                                    std::unique_ptr&lt;SharedMemory&gt; shm,
                                    const std::string&amp; sdk_version) {
...
  const ProducerID id = GetNextProducerID();
...
  std::unique_ptr&lt;ProducerEndpointImpl&gt; endpoint(new ProducerEndpointImpl(
      id, client_identity, this, task_runner_, producer, producer_name,
      sdk_version, in_process, smb_scraping_enabled));
  auto it_and_inserted = producers_.emplace(id, endpoint.get());
...
  // Producer::OnConnect() should run before Producer::OnTracingSetup(). The
  // latter may be posted by SetupSharedMemory() below, so post OnConnect() now.
  auto weak_ptr = endpoint-&gt;weak_ptr_factory_.GetWeakPtr();
  task_runner_-&gt;PostTask([weak_ptr] {
    if (weak_ptr)
      weak_ptr-&gt;producer_-&gt;OnConnect();
  });

  return std::unique_ptr&lt;ProducerEndpoint&gt;(std::move(endpoint));
}
</code></pre>
<p>在看回复消息的回调ReplyToMethodInvocation，这里比较简单，发送了invoke_method_reply消息</p>
<pre><code class="language-cpp">void HostImpl::ReplyToMethodInvocation(ClientID client_id,
                                       RequestID request_id,
                                       AsyncResult&lt;ProtoMessage&gt; reply) {
  auto client_iter = clients_.find(client_id);
  if (client_iter == clients_.end())
    return;  // client has disconnected by the time we got the async reply.

  ClientConnection* client = client_iter-&gt;second.get();
  Frame reply_frame;
  reply_frame.set_request_id(request_id);
...
  auto* reply_frame_data = reply_frame.mutable_msg_invoke_method_reply();
...
  SendFrame(client, reply_frame, reply.fd());
}
</code></pre>
<p>下面看ClientImpl::OnInvokeMethodReply，这里主要就是拿出service_proxy，并且调用EndInvoke</p>
<pre><code class="language-cpp">void ClientImpl::OnInvokeMethodReply(QueuedRequest req,
                                     const Frame::InvokeMethodReply&amp; reply) {
  base::WeakPtr&lt;ServiceProxy&gt; service_proxy = req.service_proxy;
  if (!service_proxy)
    return;
  std::unique_ptr&lt;ProtoMessage&gt; decoded_reply;
...
  const RequestID request_id = req.request_id;
  invoking_method_reply_ = true;
  service_proxy-&gt;EndInvoke(request_id, std::move(decoded_reply),
                           reply.has_more());
  invoking_method_reply_ = false;

  // If this is a streaming method and future replies will be resolved, put back
  // the |req| with the callback into the set of active requests.
  if (reply.has_more())
    queued_requests_.emplace(request_id, std::move(req));
}
</code></pre>
<p>看EndInvoke的处理，就是调用了一开始调用BeginInvoke时传入的回调，往前看InitializeConnection的回调是什么？</p>
<pre><code class="language-cpp">void ServiceProxy::EndInvoke(RequestID request_id,
                             std::unique_ptr&lt;ProtoMessage&gt; result,
                             bool has_more) {
  auto callback_it = pending_callbacks_.find(request_id);
  if (callback_it == pending_callbacks_.end()) {
    // Either we are getting a reply for a method we never invoked, or we are
    // getting a reply to a method marked drop_reply (that has been invoked
    // without binding any callback in the Defererd response object).
    PERFETTO_DFATAL("Unexpected reply received.");
    return;
  }
  DeferredBase&amp; reply_callback = callback_it-&gt;second;
  AsyncResult&lt;ProtoMessage&gt; reply(std::move(result), has_more);
  reply_callback.Resolve(std::move(reply));
  if (!has_more)
    pending_callbacks_.erase(callback_it);
}
</code></pre>
<p>再贴一次，回调是ProducerIPCClientImpl::OnConnectionInitialized</p>
<pre><code class="language-cpp">void ProducerIPCClientImpl::OnConnect() {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  connected_ = true;

  ipc::Deferred&lt;protos::gen::InitializeConnectionResponse&gt; on_init;
  on_init.Bind(
      [this](ipc::AsyncResult&lt;protos::gen::InitializeConnectionResponse&gt; resp) {
        OnConnectionInitialized(
            resp.success(),
            resp.success() ? resp-&gt;using_shmem_provided_by_producer() : false,
            resp.success() ? resp-&gt;direct_smb_patching_supported() : false,
            resp.success() ? resp-&gt;use_shmem_emulation() : false);
      });
</code></pre>
<p>接着看OnConnectionInitialized，这里就是调用了producer_-&gt;OnConnect();，还记得producer_是什么吗？就是在创建ProducerIPCClientImpl时传入的上层事件监听者，也是处理实际producer业务的对象，这里可以是HeapprofdProducer，因为接下来就是注册data source，这是与tracing业务直接相关的。</p>
<pre><code class="language-cpp">void ProducerIPCClientImpl::OnConnectionInitialized(
    bool connection_succeeded,
    bool using_shmem_provided_by_producer,
    bool direct_smb_patching_supported,
    bool use_shmem_emulation) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  // If connection_succeeded == false, the OnDisconnect() call will follow next
  // and there we'll notify the |producer_|. TODO: add a test for this.
  if (!connection_succeeded)
    return;
  is_shmem_provided_by_producer_ = using_shmem_provided_by_producer;
  direct_smb_patching_supported_ = direct_smb_patching_supported;
  // The tracing service may reject using shared memory and tell the client to
  // commit data over the socket. This can happen when the client connects to
  // the service via a relay service:
  // client &lt;-Unix socket-&gt; relay service &lt;- vsock -&gt; tracing service.
  use_shmem_emulation_ = use_shmem_emulation;
  producer_-&gt;OnConnect();

  // Bail out if the service failed to adopt our producer-allocated SMB.
  // TODO(eseckler): Handle adoption failure more gracefully.
  if (shared_memory_ &amp;&amp; !is_shmem_provided_by_producer_) {
    PERFETTO_DLOG("Service failed adopt producer-provided SMB, disconnecting.");
    Disconnect();
    return;
  }
}
</code></pre>
<p>看HeapprofdProducer::OnConnect，能看出接着就是注册data source</p>
<pre><code class="language-cpp">void HeapprofdProducer::OnConnect() {
  PERFETTO_DCHECK(state_ == kConnecting);
  state_ = kConnected;
  ResetConnectionBackoff();
  PERFETTO_LOG("Connected to the service, mode [%s].",
               mode_ == HeapprofdMode::kCentral ? "central" : "child");

  DataSourceDescriptor desc;
  desc.set_name(kHeapprofdDataSource);
  desc.set_will_notify_on_stop(true);
  endpoint_-&gt;RegisterDataSource(desc);
}
</code></pre>
<p>先是调用ProducerEndpointImpl::RegisterDataSource，这里很简单，这里的service_是执行ProducerIPCClient::Connect时传入的ProducerIPCClientImpl</p>
<pre><code class="language-cpp">void TracingServiceImpl::ProducerEndpointImpl::RegisterDataSource(
    const DataSourceDescriptor&amp; desc) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  service_-&gt;RegisterDataSource(id_, desc);
}
</code></pre>
<p>接着看ProducerIPCClientImpl::RegisterDataSource，可以看到这里的回调比较简单，也就是说对于producer,RegisterDataSource后初始化工作就结束了。</p>
<pre><code class="language-cpp">void ProducerIPCClientImpl::RegisterDataSource(
    const DataSourceDescriptor&amp; descriptor) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  if (!connected_) {
    PERFETTO_DLOG(
        "Cannot RegisterDataSource(), not connected to tracing service");
  }
  protos::gen::RegisterDataSourceRequest req;
  *req.mutable_data_source_descriptor() = descriptor;
  ipc::Deferred&lt;protos::gen::RegisterDataSourceResponse&gt; async_response;
  async_response.Bind(
      [](ipc::AsyncResult&lt;protos::gen::RegisterDataSourceResponse&gt; response) {
        if (!response)
          PERFETTO_DLOG("RegisterDataSource() failed: connection reset");
      });
  producer_port_-&gt;RegisterDataSource(req, std::move(async_response));
}
</code></pre>
<p>接着看service端的处理，这里先拿到对应的的RemoteProducer，这个producer就是在上面处理InitializeConnection时创建的。
然后通过service_endpoint调用RegisterDataSource，这里的service_endpoint和上文client端的调用RegisterDataSource的endpoint_都是ProducerEndpointImpl对象，区别是传递的service_不一样，client端的service_是ProducerIPCClientImpl，而service端就是TracingServiceImpl。这里也能看到producer的注册最终会走到TracingServiceImpl这个主要的业务对象</p>
<pre><code class="language-cpp">void ProducerIPCService::RegisterDataSource(
    const protos::gen::RegisterDataSourceRequest&amp; req,
    DeferredRegisterDataSourceResponse response) {
  RemoteProducer* producer = GetProducerForCurrentRequest();
  if (!producer) {
    PERFETTO_DLOG(
        "Producer invoked RegisterDataSource() before InitializeConnection()");
    if (response.IsBound())
      response.Reject();
    return;
  }

  const DataSourceDescriptor&amp; dsd = req.data_source_descriptor();
  GetProducerForCurrentRequest()-&gt;service_endpoint-&gt;RegisterDataSource(dsd);

  // RegisterDataSource doesn't expect any meaningful response.
  if (response.IsBound()) {
    response.Resolve(
        ipc::AsyncResult&lt;protos::gen::RegisterDataSourceResponse&gt;::Create());
  }
}
</code></pre>
<p>这里主要的处理就是将data source添加到data_sources_里</p>
<pre><code class="language-cpp">void TracingServiceImpl::RegisterDataSource(ProducerID producer_id,
                                            const DataSourceDescriptor&amp; desc) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  if (desc.name().empty()) {
    PERFETTO_DLOG("Received RegisterDataSource() with empty name");
    return;
  }

  ProducerEndpointImpl* producer = GetProducer(producer_id);
  if (!producer) {
    PERFETTO_DFATAL("Producer not found.");
    return;
  }

  // Check that the producer doesn't register two data sources with the same ID.
  // Note that we tolerate |id| == 0 because until Android T / v22 the |id|
  // field didn't exist.
  for (const auto&amp; kv : data_sources_) {
    if (desc.id() &amp;&amp; kv.second.producer_id == producer_id &amp;&amp;
        kv.second.descriptor.id() == desc.id()) {
      PERFETTO_ELOG(
          "Failed to register data source \"%s\". A data source with the same "
          "id %" PRIu64 " (name=\"%s\") is already registered for producer %d",
          desc.name().c_str(), desc.id(), kv.second.descriptor.name().c_str(),
          producer_id);
      return;
    }
  }

  PERFETTO_DLOG("Producer %" PRIu16 " registered data source \"%s\"",
                producer_id, desc.name().c_str());

  auto reg_ds = data_sources_.emplace(desc.name(),
                                      RegisteredDataSource{producer_id, desc});

  ...
}
</code></pre>
<p>至此，producer的启动初始化工作就结束了，后面就是由consumer来触发trace了，将在下一篇介绍。</p>]]></content><author><name></name></author><category term="perfetto" /><category term="performance" /><summary type="html"><![CDATA[上篇介绍了traced运行流程和大体框架，本篇将分析producer的启动流程，以heapprofd为例 代码在src/profiling/memory 从main函数跟踪，很快就看到启动的主体部分。 int StartCentralHeapprofd() { // We set this up before launching any threads, so we do not have to use a // std::atomic for g_dump_evt. g_dump_evt = new base::EventFd(); base::UnixTaskRunner task_runner; base::Watchdog::GetInstance()-&gt;Start(); // crash on exceedingly long tasks HeapprofdProducer producer(HeapprofdMode::kCentral, &amp;task_runner, /* exit_when_done= */ false); int listening_raw_socket = GetListeningSocket(); auto listening_socket = base::UnixSocket::Listen( base::ScopedFile(listening_raw_socket), &amp;producer.socket_delegate(), &amp;task_runner, base::SockFamily::kUnix, base::SockType::kStream); struct sigaction action = {}; action.sa_handler = [](int) { g_dump_evt-&gt;Notify(); }; // Allow to trigger a full dump by sending SIGUSR1 to heapprofd. // This will allow manually deciding when to dump on userdebug. PERFETTO_CHECK(sigaction(SIGUSR1, &amp;action, nullptr) == 0); task_runner.AddFileDescriptorWatch(g_dump_evt-&gt;fd(), [&amp;producer] { g_dump_evt-&gt;Clear(); producer.DumpAll(); }); producer.ConnectWithRetries(GetProducerSocket()); // TODO(fmayer): Create one producer that manages both heapprofd and Java // producers, so we do not have two connections to traced. JavaHprofProducer java_producer(&amp;task_runner); java_producer.ConnectWithRetries(GetProducerSocket()); task_runner.Run(); return 0; }]]></summary></entry><entry><title type="html">perfetto源码解析-基础框架（2）</title><link href="https://aimfly.github.io/perfetto/performance/2025/04/20/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(2).html" rel="alternate" type="text/html" title="perfetto源码解析-基础框架（2）" /><published>2025-04-20T00:00:00+00:00</published><updated>2025-04-20T00:00:00+00:00</updated><id>https://aimfly.github.io/perfetto/performance/2025/04/20/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(2)</id><content type="html" xml:base="https://aimfly.github.io/perfetto/performance/2025/04/20/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(2).html"><![CDATA[<p>接上篇，看task_runner.Run()做了什么</p>

<p>代码在src/base/unix_task_runner.cc</p>

<p>可以看到这里进入了无限循环，先是调用了UpdateWatchTasksLocked，还记得之前看到将socket添加到watch_tasks_里了</p>
<pre><code class="language-cpp">void UnixTaskRunner::Run() {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  created_thread_id_ = GetThreadId();
  quit_ = false;
  for (;;) {
    int poll_timeout_ms;
    {
      std::lock_guard&lt;std::mutex&gt; lock(lock_);
      if (quit_)
        return;
      poll_timeout_ms = GetDelayMsToNextTaskLocked();
      UpdateWatchTasksLocked();
    }
</code></pre>
<!--more-->
<p>看下UpdateWatchTasksLocked的实现，这里就能看到处理了watch_tasks_并且把fd添加到了poll_fds_</p>
<pre><code class="language-cpp">void UnixTaskRunner::UpdateWatchTasksLocked() {
  PERFETTO_DCHECK_THREAD(thread_checker_);
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  if (!watch_tasks_changed_)
    return;
  watch_tasks_changed_ = false;
#endif
  poll_fds_.clear();
  for (auto&amp; it : watch_tasks_) {
    PlatformHandle handle = it.first;
    WatchTask&amp; watch_task = it.second;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
    if (!watch_task.pending)
      poll_fds_.push_back(handle);
#else
    watch_task.poll_fd_index = poll_fds_.size();
    poll_fds_.push_back({handle, POLLIN | POLLHUP, 0});
#endif
  }
}
</code></pre>
<p>接着看Run下面的处理，可以看到使用了poll这个阻塞系统调用并且设置了超时，这里当socket fd有事件产生便会退出，下面接着调用了PostFileDescriptorWatches</p>
<pre><code class="language-cpp">    platform::BeforeMaybeBlockingSyscall();
    int ret = PERFETTO_EINTR(poll(
        &amp;poll_fds_[0], static_cast&lt;nfds_t&gt;(poll_fds_.size()), poll_timeout_ms));
    platform::AfterMaybeBlockingSyscall();
    PERFETTO_CHECK(ret &gt;= 0);
    PostFileDescriptorWatches(0 /*ignored*/);
</code></pre>
<p>看PostFileDescriptorWatches，这里主要是把有事件发生的fd（代码中的handle）绑定RunFileDescriptorWatch放进immediate_tasks_用作后续执行</p>
<pre><code class="language-cpp">    PostTask(std::bind(&amp;UnixTaskRunner::RunFileDescriptorWatch, this, handle));

void UnixTaskRunner::PostTask(std::function&lt;void()&gt; task) {
  bool was_empty;
  {
    std::lock_guard&lt;std::mutex&gt; lock(lock_);
    was_empty = immediate_tasks_.empty();
    immediate_tasks_.push_back(std::move(task));
  }
  if (was_empty)
    WakeUp();
}
</code></pre>
<p>接着看Run最后就调用了RunImmediateAndDelayedTask来执行immediate_tasks_和delayed_tasks_里的任务，这里还没有看到往delayed_tasks_放任务的地方，后续再讨论，这里使用了RunTaskWithWatchdogGuard去执行immediate_task，RunTaskWithWatchdogGuard里面设定了任务最大可执行的时间，然后执行了task,不展开，直接看执行的task就是刚刚的RunFileDescriptorWatch</p>
<pre><code class="language-cpp">void UnixTaskRunner::RunImmediateAndDelayedTask() {
  // If locking overhead becomes an issue, add a separate work queue.
  std::function&lt;void()&gt; immediate_task;
  std::function&lt;void()&gt; delayed_task;
  TimeMillis now = GetWallTimeMs();
  {
    std::lock_guard&lt;std::mutex&gt; lock(lock_);
    if (!immediate_tasks_.empty()) {
      immediate_task = std::move(immediate_tasks_.front());
      immediate_tasks_.pop_front();
    }
    ...
  }

  errno = 0;
  if (immediate_task)
    RunTaskWithWatchdogGuard(immediate_task);
  ...
}
</code></pre>
<p>看RunFileDescriptorWatch,这里取出了watch_task里的回掉，接着把回调套娃式的用RunTaskWithWatchdogGuard执行，还记得这个回调哪里传入的吗，就是在添加socket时，这个回调就是src/base/unix_socket.cc里的UnixSocket::OnEvent()</p>
<pre><code class="language-cpp">void UnixTaskRunner::RunFileDescriptorWatch(PlatformHandle fd) {
  std::function&lt;void()&gt; task;
  {
    std::lock_guard&lt;std::mutex&gt; lock(lock_);
    auto it = watch_tasks_.find(fd);
    if (it == watch_tasks_.end())
      return;
    WatchTask&amp; watch_task = it-&gt;second;
...
    task = watch_task.callback;
  }
  errno = 0;
  RunTaskWithWatchdogGuard(task);
}
</code></pre>
<p>看UnixSocket::OnEvent()，这里面根据不同状态做了不同处理，而一开始添加的用于监听的socket就是kListening状态，可以看前面new UnixSocket的那段确认，所以这里看kListening
的处理，做了accept并且又创建了新的UnixSocket对象用作管理connected的socket，然后调用了event_listener_-&gt;OnNewIncomingConnection，event_listener_是什么呢？如果再看前面new UnixSocket的那段就知道，event_listener_是HostImpl对象，这里强调一点，HostImpl对象分别对应着producer和consumer socket。</p>
<pre><code class="language-cpp">void UnixSocket::OnEvent() {
  ...
  // New incoming connection.
  if (state_ == State::kListening) {
    // There could be more than one incoming connection behind each FD watch
    // notification. Drain'em all.
    for (;;) {
      ScopedFile new_fd(
          PERFETTO_EINTR(accept(sock_raw_.fd(), nullptr, nullptr)));
      if (!new_fd)
        return;
      std::unique_ptr&lt;UnixSocket&gt; new_sock(new UnixSocket(
          event_listener_, task_runner_, std::move(new_fd), State::kConnected,
          sock_raw_.family(), sock_raw_.type(), peer_cred_mode_));
      event_listener_-&gt;OnNewIncomingConnection(this, std::move(new_sock));
    }
  }
}
</code></pre>
<p>接着看HostImpl的OnNewIncomingConnection，添加了新的client，再结合前面的代码，不同HostImpl对象分别对应着producer和consumer socket。所以上面new UnixSocket时依然传递Listening状态socket里的event_listener_</p>
<pre><code class="language-cpp">void HostImpl::OnNewIncomingConnection(
    base::UnixSocket*,
    std::unique_ptr&lt;base::UnixSocket&gt; new_conn) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  std::unique_ptr&lt;ClientConnection&gt; client(new ClientConnection());
  ClientID client_id = ++last_client_id_;
  clients_by_socket_[new_conn.get()] = client.get();
  client-&gt;id = client_id;
  client-&gt;sock = std::move(new_conn);
  client-&gt;sock-&gt;SetTxTimeout(socket_tx_timeout_ms_);
  clients_[client_id] = std::move(client);
}
</code></pre>
<p>连接以后就是收发数据了吧，看UnixSocket::OnEvent()的处理，这里调用了HostImpl里的OnDataAvailable</p>
<pre><code class="language-cpp">void UnixSocket::OnEvent() {
  if (state_ == State::kDisconnected)
    return;  // Some spurious event, typically queued just before Shutdown().

  if (state_ == State::kConnected)
    return event_listener_-&gt;OnDataAvailable(this);
</code></pre>
<p>看OnDataAvailable做了啥，这里做了数据的反序列化，不展开，最终的数据是Frame，也即perfetto::protos::gen::IPCFrame，这里看到了第一个用protobuf的地方，它的定义在protos/perfetto/ipc/wire_protocol.proto</p>
<pre><code class="language-cpp">void HostImpl::OnDataAvailable(base::UnixSocket* sock) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  auto it = clients_by_socket_.find(sock);
  if (it == clients_by_socket_.end())
    return;
  ClientConnection* client = it-&gt;second;
  BufferedFrameDeserializer&amp; frame_deserializer = client-&gt;frame_deserializer;
...
  for (;;) {
    std::unique_ptr&lt;Frame&gt; frame = frame_deserializer.PopNextFrame();
    if (!frame)
      break;
    OnReceivedFrame(client, *frame);
  }
}
</code></pre>
<p>看一下wire_protocol.proto的内容，这里面定义了不同的消息，大概可以猜到有绑定服务，并且回复带上服务可提供的方法，然后执行方法等，看OnReceivedFrame里便是对应到不同的Client请求message来调用不同的处理方法，下面先看BindService</p>
<pre><code class="language-cpp">message IPCFrame {
  // Client -&gt; Host.
  message BindService { optional string service_name = 1; }

  // Host -&gt; Client.
  message BindServiceReply {
    message MethodInfo {
      optional uint32 id = 1;
      optional string name = 2;
    }
    optional bool success = 1;
    optional uint32 service_id = 2;
    repeated MethodInfo methods = 3;
  }

  // Client -&gt; Host.
  message InvokeMethod {
    // BindServiceReply.id.
    optional uint32 service_id = 1;

    // BindServiceReply.method.id.
    optional uint32 method_id = 2;

    // Proto-encoded request argument.
    optional bytes args_proto = 3;

    // When true the client specifies that a reply is not needed. The use case
    // is a method with an empty, where the client doesn't care about the
    // success/failure of the method invocation and rather prefers avoiding the
    // IPC roundtrip + context switch associated with the reply.
    optional bool drop_reply = 4;
  }
...
</code></pre>
<p>这里是不是看到了GetServiceByName来获取ExposedService，而前面也提到过ExposedService。</p>
<pre><code class="language-cpp">void HostImpl::OnBindService(ClientConnection* client, const Frame&amp; req_frame) {
  // Binding a service doesn't do anything major. It just returns back the
  // service id and its method map.
  const Frame::BindService&amp; req = req_frame.msg_bind_service();
  Frame reply_frame;
  reply_frame.set_request_id(req_frame.request_id());
  auto* reply = reply_frame.mutable_msg_bind_service_reply();
  const ExposedService* service = GetServiceByName(req.service_name());
  if (service) {
    reply-&gt;set_success(true);
    reply-&gt;set_service_id(service-&gt;id);
    uint32_t method_id = 1;  // method ids start at index 1.
    for (const auto&amp; desc_method : service-&gt;instance-&gt;GetDescriptor().methods) {
      Frame::BindServiceReply::MethodInfo* method_info = reply-&gt;add_methods();
      method_info-&gt;set_name(desc_method.name);
      method_info-&gt;set_id(method_id++);
    }
  }
  SendFrame(client, reply_frame);
}
</code></pre>
<p>再回过头看添加ExposedService的时机，就是ServiceIPCHostImpl::DoStart里，注意producer_ipc_port和consumer_ipc_port_即为HostImpl对象，它们分别添加的服务是ProducerIPCService和ConsumerIPCService。</p>
<pre><code class="language-cpp">bool ServiceIPCHostImpl::DoStart() {
...
  svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_,
                                        init_opts_);
...
  for (auto&amp; producer_ipc_port : producer_ipc_ports_) {
    bool producer_service_exposed = producer_ipc_port-&gt;ExposeService(
        std::unique_ptr&lt;ipc::Service&gt;(new ProducerIPCService(svc_.get())));
    PERFETTO_CHECK(producer_service_exposed);
...
  }

  bool consumer_service_exposed = consumer_ipc_port_-&gt;ExposeService(
      std::unique_ptr&lt;ipc::Service&gt;(new ConsumerIPCService(svc_.get())));
  PERFETTO_CHECK(consumer_service_exposed);

  return true;
}
</code></pre>
<p>看一下ExposeService，这里通过GetDescriptor得到service name,然后在ProducerIPCService或者ConsumerIPCService找GetDescriptor，是不是发现找不到？</p>
<pre><code class="language-cpp">bool HostImpl::ExposeService(std::unique_ptr&lt;Service&gt; service) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  const std::string&amp; service_name = service-&gt;GetDescriptor().service_name;
  if (GetServiceByName(service_name)) {
    PERFETTO_DLOG("Duplicate ExposeService(): %s", service_name.c_str());
    return false;
  }
  service-&gt;use_shmem_emulation_ =
      sock() &amp;&amp; !base::SockShmemSupported(sock()-&gt;family());
  ServiceID sid = ++last_service_id_;
  ExposedService exposed_service(sid, service_name, std::move(service));
  services_.emplace(sid, std::move(exposed_service));
  return true;
}
</code></pre>
<p>在src/tracing/ipc/service/producer_ipc_service.h看ProducerIPCService的声明，发现它继承于protobuf ProducerPort</p>
<pre><code class="language-cpp">class ProducerIPCService : public protos::gen::ProducerPort {
 public:
</code></pre>
<p>继续在ProducerPort里找GetDescriptor，还是找不到，这个地方很特别，它是通过产生protobuf源代码时用plugin去修改了代码来生成的，plugin代码在src/ipc/protoc_plugin/ipc_plugin.cc，Android.bp可以看到如何使用它。</p>

<p>接着看生成的代码out/soong/.intermediates/external/perfetto/perfetto_protos_perfetto_ipc_ipc_gen/gen/external/perfetto/protos/perfetto/ipc/producer_port.ipc.cc，能看到GetDescriptor</p>
<pre><code class="language-cpp">const ::perfetto::ipc::ServiceDescriptor&amp; ProducerPort::GetDescriptorStatic() {
  static auto* instance = NewDescriptor();
  return *instance;
}

// Host-side definitions.
ProducerPort::~ProducerPort() = default;

const ::perfetto::ipc::ServiceDescriptor&amp; ProducerPort::GetDescriptor() {
  return GetDescriptorStatic();
}
</code></pre>
<p>并且在文件的开头能看到service_name是什么，和重要的数据结构desc-&gt;methods的初始化，再回过去看HostImpl::OnBindService也就知道返回给Client的methods是从哪来的了。</p>
<pre><code class="language-cpp">  auto* desc = new ::perfetto::ipc::ServiceDescriptor();
  desc-&gt;service_name = "ProducerPort";

  desc-&gt;methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
     "InitializeConnection",
     &amp;_IPC_Decoder&lt;InitializeConnectionRequest&gt;,
     &amp;_IPC_Decoder&lt;InitializeConnectionResponse&gt;,
     &amp;_IPC_Invoker&lt;ProducerPort, InitializeConnectionRequest, InitializeConnectionResponse, &amp;ProducerPort::InitializeConnection&gt;});

  desc-&gt;methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
     "RegisterDataSource",
     &amp;_IPC_Decoder&lt;RegisterDataSourceRequest&gt;,
     &amp;_IPC_Decoder&lt;RegisterDataSourceResponse&gt;,
     &amp;_IPC_Invoker&lt;ProducerPort, RegisterDataSourceRequest, RegisterDataSourceResponse, &amp;ProducerPort::RegisterDataSource&gt;});

  desc-&gt;methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
     "UnregisterDataSource",
     &amp;_IPC_Decoder&lt;UnregisterDataSourceRequest&gt;,
     &amp;_IPC_Decoder&lt;UnregisterDataSourceResponse&gt;,
     &amp;_IPC_Invoker&lt;ProducerPort, UnregisterDataSourceRequest, UnregisterDataSourceResponse, &amp;ProducerPort::UnregisterDataSource&gt;});
</code></pre>
<p>perfetto::ipc::ServiceDescriptor::Method是一个结构体，不难看出最后一个invoker即为对应的回调函数。</p>
<pre><code class="language-cpp">class ServiceDescriptor {
 public:
  struct Method {
    const char* name;

    // DecoderFunc is pointer to a function that takes a string in input
    // containing protobuf encoded data and returns a decoded protobuf message.
    using DecoderFunc = std::unique_ptr&lt;ProtoMessage&gt; (*)(const std::string&amp;);

    // Function pointer to decode the request argument of the method.
    DecoderFunc request_proto_decoder;

    // Function pointer to decoded the reply argument of the method.
    DecoderFunc reply_proto_decoder;

    // Function pointer that dispatches the generic request to the corresponding
    // method implementation.
    using InvokerFunc = void (*)(Service*,
                                 const ProtoMessage&amp; /* request_args */,
                                 DeferredBase /* deferred_reply */);
    InvokerFunc invoker;
  };
</code></pre>
<p>继续看HostImpl::OnInvokeMethod的处理，前面已经看到InvokeMethod也是IPCFrame里面的一个消息，可以从它的处理中看到，通过请求的method_id找到对应的method结构体并且调用了invoker</p>
<pre><code class="language-cpp">void HostImpl::OnInvokeMethod(ClientConnection* client,
                              const Frame&amp; req_frame) {
...
  const uint32_t method_id = req.method_id();
  if (method_id == 0 || method_id &gt; methods.size())
    return SendFrame(client, reply_frame);

  const ServiceDescriptor::Method&amp; method = methods[method_id - 1];
...
  method.invoker(service, *decoded_req_args, std::move(deferred_reply));
  service-&gt;received_fd_ = nullptr;
  service-&gt;client_info_ = ClientInfo();
}
</code></pre>
<p>例如如果是producer的InitializeConnection方法，那么它对应的函数即是ProducerIPCService::InitializeConnection，可以看到这里调用了core_service_(TracingService)的ConnectProducer来注册producer，而前面为了laze start而注册的builtin producer也是用的这个方法。</p>
<pre><code class="language-cpp">// Called by the remote Producer through the IPC channel soon after connecting.
void ProducerIPCService::InitializeConnection(
    const protos::gen::InitializeConnectionRequest&amp; req,
    DeferredInitializeConnectionResponse response) {
  const auto&amp; client_info = ipc::Service::client_info();
  const ipc::ClientID ipc_client_id = client_info.client_id();
  PERFETTO_CHECK(ipc_client_id);

  if (producers_.count(ipc_client_id) &gt; 0) {
    PERFETTO_DLOG(
        "The remote Producer is trying to re-initialize the connection");
    return response.Reject();
  }
...
  // ConnectProducer will call OnConnect() on the next task.
  producer-&gt;service_endpoint = core_service_-&gt;ConnectProducer(
      producer.get(), client_identity, req.producer_name(),
      req.shared_memory_size_hint_bytes(),
      /*in_process=*/false, smb_scraping_mode,
      req.shared_memory_page_size_hint_bytes(), std::move(shmem),
      req.sdk_version());
</code></pre>
<p>至此也就理清了traced大体的框架和通信机制。</p>

<p>以下是简要的模块图以便于理解。</p>

<p><img src="/assets/images/traced_modules.png" alt="pic1" /></p>

<p>ServiceIPCHostImpl是在main里创建的一个对象，包含了一个TracingService对象，和对应producer与consumer socket的不同HostImpl对象，</p>

<p>HostImpl里包含了UnixSocket对象用于处理socket状态和事件相关，具体的处理又会回调到HostImpl里的方法</p>

<p>HostImpl里还包含了ProducerIPCService或者ConsumerIPCService用于处理实际的用protobuf定义的客户端消息</p>]]></content><author><name></name></author><category term="perfetto" /><category term="performance" /><summary type="html"><![CDATA[接上篇，看task_runner.Run()做了什么 代码在src/base/unix_task_runner.cc 可以看到这里进入了无限循环，先是调用了UpdateWatchTasksLocked，还记得之前看到将socket添加到watch_tasks_里了 void UnixTaskRunner::Run() { PERFETTO_DCHECK_THREAD(thread_checker_); created_thread_id_ = GetThreadId(); quit_ = false; for (;;) { int poll_timeout_ms; { std::lock_guard&lt;std::mutex&gt; lock(lock_); if (quit_) return; poll_timeout_ms = GetDelayMsToNextTaskLocked(); UpdateWatchTasksLocked(); }]]></summary></entry><entry><title type="html">perfetto源码解析-基础框架（1）</title><link href="https://aimfly.github.io/perfetto/performance/2025/04/19/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(1).html" rel="alternate" type="text/html" title="perfetto源码解析-基础框架（1）" /><published>2025-04-19T00:00:00+00:00</published><updated>2025-04-19T00:00:00+00:00</updated><id>https://aimfly.github.io/perfetto/performance/2025/04/19/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(1)</id><content type="html" xml:base="https://aimfly.github.io/perfetto/performance/2025/04/19/perfetto%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90(1).html"><![CDATA[<p>perfetto是google开源的一套系统级别的性能收集与分析工具。</p>

<p>笔者试图在源码的层面分析它的工作原理。</p>

<p>源代码基于AOSP里的external/perfetto版本android-15.0.0_r3。</p>

<p>下图为Android平台上perfetto的主体框架，通过debug log也把主要的producer和data source列在其中
<img src="/assets/images/perfetto_arch.png" alt="pic1" />
<!--more-->
图中，traced是perfetto主要的常驻模块，它提供/dev/socket/traced_producer给其他性能数据生产者注册使用，
提供/dev/socket/traced_consumer供消费者使用，如图主要的消费者就是perfetto命令行，perfetto命令将性能数据记在文件中，由其他的外部工具获取使用</p>

<p>下面看traced启动做了什么
主要入口在 src/traced/service/service.cc</p>
<pre><code class="language-cpp">int PERFETTO_EXPORT_ENTRYPOINT ServiceMain(int argc, char** argv) {
  enum LongOption {
    OPT_VERSION = 1000,
    OPT_SET_SOCKET_PERMISSIONS = 1001,
    OPT_BACKGROUND,
    OPT_ENABLE_RELAY_ENDPOINT
  };
</code></pre>
<p>首先是命令行的解析，然后是创建service和task_runner，
task_runner作为后续task的执行者处理各种异步事件</p>
<pre><code class="language-cpp">  base::UnixTaskRunner task_runner;
  std::unique_ptr&lt;ServiceIPCHost&gt; svc;
  TracingService::InitOpts init_opts = {};
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
  init_opts.compressor_fn = &amp;ZlibCompressFn;
#endif
  if (enable_relay_endpoint)
    init_opts.enable_relay_endpoint = true;
  svc = ServiceIPCHost::CreateInstance(&amp;task_runner, init_opts);
</code></pre>
<p>下面通过进程空间的环境变量拿到producer和cosumer两个socket,这里的socket是在perfetto.rc定义，init里创建再通过环境变量传递给fork出来的service,这是android control socket的机制</p>
<pre><code class="language-cpp">  const char* env_prod = getenv("ANDROID_SOCKET_traced_producer");
  const char* env_cons = getenv("ANDROID_SOCKET_traced_consumer");
  PERFETTO_CHECK((!env_prod &amp;&amp; !env_cons) || (env_prod &amp;&amp; env_cons));
  bool started;
  if (env_prod) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
    PERFETTO_CHECK(false);
#else
    base::ScopedFile producer_fd(atoi(env_prod));
    base::ScopedFile consumer_fd(atoi(env_cons));
    started = svc-&gt;Start(std::move(producer_fd), std::move(consumer_fd));
#endif
</code></pre>
<p>然后看Start做了什么，在src/tracing/ipc/service/service_ipc_host_impl.cc</p>
<pre><code class="language-cpp">bool ServiceIPCHostImpl::Start(base::ScopedSocketHandle producer_socket_fd,
                               base::ScopedSocketHandle consumer_socket_fd) {
  PERFETTO_CHECK(!svc_);  // Check if already started.

  // Initialize the IPC transport.
  producer_ipc_ports_.emplace_back(
      ipc::Host::CreateInstance(std::move(producer_socket_fd), task_runner_));
  consumer_ipc_port_ =
      ipc::Host::CreateInstance(std::move(consumer_socket_fd), task_runner_);
  return DoStart();
}
</code></pre>
<p>这里可以看到基于两个socket创建了Host instance, 并且传入了task_runner_</p>

<p>再看host实现 src/ipc/host_impl.cc</p>
<pre><code class="language-cpp">std::unique_ptr&lt;Host&gt; Host::CreateInstance(base::ScopedSocketHandle socket_fd,
                                           base::TaskRunner* task_runner) {
  std::unique_ptr&lt;HostImpl&gt; host(
      new HostImpl(std::move(socket_fd), task_runner));
  if (!host-&gt;sock() || !host-&gt;sock()-&gt;is_listening())
    return nullptr;
  return std::unique_ptr&lt;Host&gt;(std::move(host));
}
</code></pre>
<p>继续跟踪HostImpl的构造</p>
<pre><code class="language-cpp">HostImpl::HostImpl(base::ScopedSocketHandle socket_fd,
                   base::TaskRunner* task_runner)
    : task_runner_(task_runner), weak_ptr_factory_(this) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  sock_ = base::UnixSocket::Listen(std::move(socket_fd), this, task_runner_,
                                   kHostSockFamily, base::SockType::kStream);
}
</code></pre>
<p>继续看Listen</p>
<pre><code class="language-cpp">std::unique_ptr&lt;UnixSocket&gt; UnixSocket::Listen(ScopedSocketHandle fd,
                                               EventListener* event_listener,
                                               TaskRunner* task_runner,
                                               SockFamily sock_family,
                                               SockType sock_type) {
  return std::unique_ptr&lt;UnixSocket&gt;(new UnixSocket(
      event_listener, task_runner, std::move(fd), State::kListening,
      sock_family, sock_type, SockPeerCredMode::kDefault));
}
</code></pre>
<p>然后来到这里 src/base/unix_socket.cc</p>
<pre><code class="language-cpp">UnixSocket::UnixSocket(EventListener* event_listener,
                       TaskRunner* task_runner,
                       ScopedSocketHandle adopt_fd,
                       State adopt_state,
                       SockFamily sock_family,
                       SockType sock_type,
                       SockPeerCredMode peer_cred_mode)
    : peer_cred_mode_(peer_cred_mode),
      event_listener_(event_listener),
      task_runner_(task_runner),
      weak_ptr_factory_(this) {
  state_ = State::kDisconnected;
  if (adopt_state == State::kDisconnected) {
    PERFETTO_DCHECK(!adopt_fd);
</code></pre>
<p>往下看会来到关键点，将socket通过AddFileDescriptorWatch传给task_runner_，并且注册了callback，熟悉poll或者epoll机制的大概能猜到task_runner_的运作机制了</p>
<pre><code class="language-cpp">  WeakPtr&lt;UnixSocket&gt; weak_ptr = weak_ptr_factory_.GetWeakPtr();

  task_runner_-&gt;AddFileDescriptorWatch(sock_raw_.watch_handle(), [weak_ptr] {
    if (weak_ptr)
      weak_ptr-&gt;OnEvent();
  });
}
</code></pre>
<p>再看AddFileDescriptorWatch实现，主要是更新watch_tasks_。这里告一段落，watch_tasks_会在后续UnixTaskRunner Run的时候用起来</p>
<pre><code class="language-cpp">void UnixTaskRunner::AddFileDescriptorWatch(PlatformHandle fd,
                                            std::function&lt;void()&gt; task) {
  PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
  {
    std::lock_guard&lt;std::mutex&gt; lock(lock_);
    PERFETTO_DCHECK(!watch_tasks_.count(fd));
    WatchTask&amp; watch_task = watch_tasks_[fd];
    watch_task.callback = std::move(task);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
    watch_task.pending = false;
#else
    watch_task.poll_fd_index = SIZE_MAX;
#endif
    watch_tasks_changed_ = true;
  }
  WakeUp();
}
</code></pre>
<p>再回到bool ServiceIPCHostImpl::Start那里看DoStart</p>
<pre><code class="language-cpp">bool ServiceIPCHostImpl::DoStart() {
  // Create and initialize the platform-independent tracing business logic.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  std::unique_ptr&lt;SharedMemory::Factory&gt; shm_factory(
      new SharedMemoryWindows::Factory());
#else
  std::unique_ptr&lt;SharedMemory::Factory&gt; shm_factory(
      new PosixSharedMemory::Factory());
#endif
  svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_,
                                        init_opts_);
</code></pre>
<p>这里创建了TracingService，和SharedMemory工厂，这里暂且不讨论它们，往下看</p>

<p>下面会通过ExposeService添加producer和cosumer的service到services_里。services_是很有意思的东西，下面会细说</p>
<pre><code class="language-cpp">bool HostImpl::ExposeService(std::unique_ptr&lt;Service&gt; service) {
  PERFETTO_DCHECK_THREAD(thread_checker_);
  const std::string&amp; service_name = service-&gt;GetDescriptor().service_name;
  if (GetServiceByName(service_name)) {
    PERFETTO_DLOG("Duplicate ExposeService(): %s", service_name.c_str());
    return false;
  }
  service-&gt;use_shmem_emulation_ =
      sock() &amp;&amp; !base::SockShmemSupported(sock()-&gt;family());
  ServiceID sid = ++last_service_id_;
  ExposedService exposed_service(sid, service_name, std::move(service));
  services_.emplace(sid, std::move(exposed_service));
  return true;
}
</code></pre>
<p>到这里socket部分的初始化就结束了，返回到ServiceMain</p>

<p>下面看到builtin producers的注册，由注释能看出，这部分poducer是用于动态启动的，例如当需要heapprofd时，通过设置prop来拉起进程，</p>
<pre><code class="language-cpp">  // Advertise builtin producers only on in-tree builds. These producers serve
  // only to dynamically start heapprofd and other services via sysprops, but
  // that can only ever happen in in-tree builds.
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  BuiltinProducer builtin_producer(&amp;task_runner, /*lazy_stop_delay_ms=*/30000);
  builtin_producer.ConnectInProcess(svc-&gt;service());
#endif
</code></pre>
<p>接着来到 src/traced/service/builtin_producer.cc，这里用与注册的刚好是上面ServiceIPCHostImpl创建的TracingService</p>
<pre><code class="language-cpp">void BuiltinProducer::ConnectInProcess(TracingService* svc) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // TODO(primiano): ConnectProducer should take a base::PlatformProcessId not
  // pid_t, as they are different on Windows. But that is a larger refactoring
  // and not worth given this is the only use case where it clashes.
  const pid_t cur_proc_id = 0;
#else
  const pid_t cur_proc_id = base::GetProcessId();
#endif
  endpoint_ = svc-&gt;ConnectProducer(
      this, ClientIdentity(base::GetCurrentUserId(), cur_proc_id), "traced",
      /*shared_memory_size_hint_bytes=*/16 * 1024, /*in_process=*/true,
      TracingService::ProducerSMBScrapingMode::kDisabled,
      /*shared_memory_page_size_hint_bytes=*/4096);
}

void BuiltinProducer::OnConnect() {
  DataSourceDescriptor metatrace_dsd;
  metatrace_dsd.set_name(MetatraceWriter::kDataSourceName);
  metatrace_dsd.set_will_notify_on_stop(true);
  endpoint_-&gt;RegisterDataSource(metatrace_dsd);
  {
    DataSourceDescriptor lazy_heapprofd_dsd;
    lazy_heapprofd_dsd.set_name(kHeapprofdDataSourceName);
    endpoint_-&gt;RegisterDataSource(lazy_heapprofd_dsd);
</code></pre>
<p>例如这部分代码，设置了traced.lazy.heapprofd，这部分代码是在consumer通过消息请求SetupDataSource时触发。</p>
<pre><code class="language-cpp">constexpr char kLazyHeapprofdPropertyName[] = "traced.lazy.heapprofd";
void BuiltinProducer::SetupDataSource(DataSourceInstanceID ds_id,
                                      const DataSourceConfig&amp; ds_config) {
  if (ds_config.name() == kHeapprofdDataSourceName ||
      ds_config.name() == kJavaHprofDataSourceName) {
    SetAndroidProperty(kLazyHeapprofdPropertyName, "1");
    lazy_heapprofd_.generation++;
    lazy_heapprofd_.instance_ids.emplace(ds_id);
    return;
  }
</code></pre>
<p>而查看了heapprofd.rc，它刚好控制了heapprofd的启动</p>
<pre><code class="language-cpp">on property:traced.lazy.heapprofd=1
    start heapprofd
</code></pre>
<p>接着再回到ServiceMain能看到task_runner的启动和log，</p>
<pre><code class="language-cpp">  PERFETTO_ILOG("Started traced, listening on %s %s", GetProducerSocket(),
                GetConsumerSocket());
  task_runner.Run();
</code></pre>
<p>至此总结一下前面提到的主要任务包括初始化socket,添加需要设置prop拉起的producer</p>

<p>未完待续</p>]]></content><author><name></name></author><category term="perfetto" /><category term="performance" /><summary type="html"><![CDATA[perfetto是google开源的一套系统级别的性能收集与分析工具。 笔者试图在源码的层面分析它的工作原理。 源代码基于AOSP里的external/perfetto版本android-15.0.0_r3。 下图为Android平台上perfetto的主体框架，通过debug log也把主要的producer和data source列在其中]]></summary></entry><entry><title type="html">编译arm平台Gnu toolchain</title><link href="https://aimfly.github.io/arm/compile/gcc/2023/08/24/%E7%BC%96%E8%AF%91ARM%E5%B9%B3%E5%8F%B0%E4%BD%BF%E7%94%A8%E7%9A%84Gnu-toolchain.html" rel="alternate" type="text/html" title="编译arm平台Gnu toolchain" /><published>2023-08-24T00:00:00+00:00</published><updated>2023-08-24T00:00:00+00:00</updated><id>https://aimfly.github.io/arm/compile/gcc/2023/08/24/%E7%BC%96%E8%AF%91ARM%E5%B9%B3%E5%8F%B0%E4%BD%BF%E7%94%A8%E7%9A%84Gnu-toolchain</id><content type="html" xml:base="https://aimfly.github.io/arm/compile/gcc/2023/08/24/%E7%BC%96%E8%AF%91ARM%E5%B9%B3%E5%8F%B0%E4%BD%BF%E7%94%A8%E7%9A%84Gnu-toolchain.html"><![CDATA[<p>本文描述如何在x86平台编译arm平台使用Gnu toolchain，编译其他平台版本类似。</p>

<p>首先从ARM Gnu Toolchain<a href="https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads">下载页面</a>下载源码并解压。</p>

<p>编译gcc需要gmp，mpc，mpfr模块，从<a href="https://ftp.gnu.org/gnu/">https://ftp.gnu.org/gnu/</a>下载。</p>

<p>配置并编译gmp，mpc，mpfr：
<!--more--></p>

<pre><code>cd /home/testing/gcc_build/gmp-6.2.1
#prefix指定安装路径，host用来指定该模块运行平台，target用来指定模块处理的目标平台，host需要是本地交叉编译器命令的前缀，否则出现找不到编译命令
./configure --host=arm-linux-gnueabi --target=arm-linux-gnueabi --prefix=/home/testing/gcc_build/gmp-6.2.1/install
make &amp;&amp; make install

#进入mpfr目录编译mpfr，这里--with-gmp需要指定之前编译并安装gmp模块的位置
./configure --host=arm-linux-gnueabi --target=arm-linux-gnueabi --prefix=/home/testing/gcc_build/mpfr-4.1.0/install --with-gmp=/home/testing/gcc_build/gmp-6.2.1/install
make &amp;&amp; make install

#编译mpc
./configure --host=arm-linux-gnueabi --target=arm-linux-gnueabi --prefix=/home/testing/gcc_build/mpc-1.2.1/install --with-gmp=/home/testing/gcc_build/gmp-6.2.1/install --with-mpfr=/home/testing/gcc_build/mpfr-4.1.0/install
make &amp;&amp; make install

</code></pre>

<p>配置并编译gcc：</p>

<pre><code>cd /home/testing/arm-gnu-toolchain-src-snapshot-12.3.rel1/

#因为有时配置makefile时会出现参数错误需要重新配置的情况，所以不要直接在源码目录执行configure
mkdir build
cd build
#一定要用--enable-languages指定gcc处理语言，否则编译时会因为缺少处理特定语言的模块而失败
../configure --host=arm-linux-gnueabi --target=arm-linux-gnueabi --with-mpc=/home/testing/gcc_build/mpc-1.2.1/install --with-gmp=/home/testing/gcc_build/gmp-6.2.1/install --with-mpfr=/home/testing/gcc_build/mpfr-4.1.0/install --prefix=/home/testing/arm-gnu-toolchain-src-snapshot-12.3.rel1/build/install --enable-languages=c,c++
make &amp;&amp; make install
</code></pre>

<p>编译时可能会出现有些宏未定义，这是因为gcc编译时有一些内置宏，而这些宏可能在高版本才有，所以用低版本的gcc编译高版本gcc时可能会出现宏找不到的情况</p>

<p>gcc内置宏可以用如下命令查看：</p>
<pre><code>arm-linux-gnueabi-gcc -dM -E - &lt; /dev/null
</code></pre>]]></content><author><name></name></author><category term="arm" /><category term="compile" /><category term="gcc" /><summary type="html"><![CDATA[本文描述如何在x86平台编译arm平台使用Gnu toolchain，编译其他平台版本类似。 首先从ARM Gnu Toolchain下载页面下载源码并解压。 编译gcc需要gmp，mpc，mpfr模块，从https://ftp.gnu.org/gnu/下载。 配置并编译gmp，mpc，mpfr：]]></summary></entry><entry><title type="html">git cherry-pick导致的预期之外的冲突</title><link href="https://aimfly.github.io/git/cherry-pick/merge/2019/12/31/git-cherry-pick%E5%AF%BC%E8%87%B4%E7%9A%84%E9%A2%84%E6%9C%9F%E4%B9%8B%E5%A4%96%E7%9A%84%E5%86%B2%E7%AA%81.html" rel="alternate" type="text/html" title="git cherry-pick导致的预期之外的冲突" /><published>2019-12-31T00:00:00+00:00</published><updated>2019-12-31T00:00:00+00:00</updated><id>https://aimfly.github.io/git/cherry-pick/merge/2019/12/31/git%20cherry-pick%E5%AF%BC%E8%87%B4%E7%9A%84%E9%A2%84%E6%9C%9F%E4%B9%8B%E5%A4%96%E7%9A%84%E5%86%B2%E7%AA%81</id><content type="html" xml:base="https://aimfly.github.io/git/cherry-pick/merge/2019/12/31/git-cherry-pick%E5%AF%BC%E8%87%B4%E7%9A%84%E9%A2%84%E6%9C%9F%E4%B9%8B%E5%A4%96%E7%9A%84%E5%86%B2%E7%AA%81.html"><![CDATA[<p>在使用git开发时，同事合并分支时遇到了一个奇怪的冲突，不是自己修改的文件，并且此前已确认源分支并没用多于目标分支的修改。</p>

<p>问题的原因后来发现是cherry-pick和merge的混用导致。</p>

<!--more-->

<p><img src="/assets/images/image2019-12-31-post1.png" alt="pic1" /></p>

<p>发生冲突的操作如下</p>

<ol>
  <li>
    <p>从master拉出分支Branch1开发</p>
  </li>
  <li>
    <p>将master中的commit通过cherry-pick提交到Branch1上</p>
  </li>
  <li>
    <p>master上有对cherry-pick部分新的修改</p>
  </li>
  <li>
    <p>修改Branch1上不同部分并提交，然后merge进master</p>
  </li>
</ol>

<p>冲突的原因是cherry-pick产生的commit并不会与原commit建立关联，此时master上新修改不会认为是一次递进提交，在merge操作时就会根据内容进行冲突判定。</p>

<p>所以如有些地方提到过，不要cherry-pick到一个会往回merge的分支。一般cherry-pick用于将release上的hotfix合入master比较合适，对于需要维护多个release的项目而言。</p>]]></content><author><name></name></author><category term="git" /><category term="cherry-pick" /><category term="merge" /><summary type="html"><![CDATA[在使用git开发时，同事合并分支时遇到了一个奇怪的冲突，不是自己修改的文件，并且此前已确认源分支并没用多于目标分支的修改。 问题的原因后来发现是cherry-pick和merge的混用导致。]]></summary></entry></feed>