Coverage Report

Created: 2025-12-31 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/perfetto/src/tracing/service/tracing_service_impl.cc
Line
Count
Source
1
/*
2
 * Copyright (C) 2017 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include "src/tracing/service/tracing_service_impl.h"
18
19
#include <limits.h>
20
#include <string.h>
21
22
#include <algorithm>
23
#include <cinttypes>
24
#include <cstdint>
25
#include <limits>
26
#include <optional>
27
#include <string>
28
#include <unordered_set>
29
30
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
31
    !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
32
#include <sys/uio.h>
33
#include <sys/utsname.h>
34
#include <unistd.h>
35
#endif
36
37
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
38
    PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
39
#include "src/android_internal/lazy_library_loader.h"    // nogncheck
40
#include "src/android_internal/tracing_service_proxy.h"  // nogncheck
41
#endif
42
43
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
44
    PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
45
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
46
#define PERFETTO_HAS_CHMOD
47
#include <sys/stat.h>
48
#endif
49
50
#include "perfetto/base/build_config.h"
51
#include "perfetto/base/status.h"
52
#include "perfetto/base/task_runner.h"
53
#include "perfetto/ext/base/android_utils.h"
54
#include "perfetto/ext/base/clock_snapshots.h"
55
#include "perfetto/ext/base/file_utils.h"
56
#include "perfetto/ext/base/metatrace.h"
57
#include "perfetto/ext/base/string_utils.h"
58
#include "perfetto/ext/base/string_view.h"
59
#include "perfetto/ext/base/sys_types.h"
60
#include "perfetto/ext/base/utils.h"
61
#include "perfetto/ext/base/uuid.h"
62
#include "perfetto/ext/base/version.h"
63
#include "perfetto/ext/base/watchdog.h"
64
#include "perfetto/ext/tracing/core/basic_types.h"
65
#include "perfetto/ext/tracing/core/client_identity.h"
66
#include "perfetto/ext/tracing/core/consumer.h"
67
#include "perfetto/ext/tracing/core/observable_events.h"
68
#include "perfetto/ext/tracing/core/producer.h"
69
#include "perfetto/ext/tracing/core/shared_memory.h"
70
#include "perfetto/ext/tracing/core/shared_memory_abi.h"
71
#include "perfetto/ext/tracing/core/trace_packet.h"
72
#include "perfetto/ext/tracing/core/trace_writer.h"
73
#include "perfetto/protozero/scattered_heap_buffer.h"
74
#include "perfetto/protozero/static_buffer.h"
75
#include "perfetto/tracing/core/data_source_descriptor.h"
76
#include "perfetto/tracing/core/tracing_service_capabilities.h"
77
#include "perfetto/tracing/core/tracing_service_state.h"
78
#include "src/android_stats/statsd_logging_helper.h"
79
#include "src/protozero/filtering/message_filter.h"
80
#include "src/protozero/filtering/string_filter.h"
81
#include "src/tracing/core/shared_memory_arbiter_impl.h"
82
#include "src/tracing/service/packet_stream_validator.h"
83
#include "src/tracing/service/trace_buffer.h"
84
85
#include "protos/perfetto/common/builtin_clock.gen.h"
86
#include "protos/perfetto/common/builtin_clock.pbzero.h"
87
#include "protos/perfetto/common/trace_stats.pbzero.h"
88
#include "protos/perfetto/config/trace_config.pbzero.h"
89
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
90
#include "protos/perfetto/trace/perfetto/tracing_service_event.pbzero.h"
91
#include "protos/perfetto/trace/remote_clock_sync.pbzero.h"
92
#include "protos/perfetto/trace/system_info.pbzero.h"
93
#include "protos/perfetto/trace/trace_packet.pbzero.h"
94
#include "protos/perfetto/trace/trace_uuid.pbzero.h"
95
#include "protos/perfetto/trace/trigger.pbzero.h"
96
97
// General note: this class must assume that Producers are malicious and will
98
// try to crash / exploit this class. We can trust pointers because they come
99
// from the IPC layer, but we should never assume that that the producer calls
100
// come in the right order or their arguments are sane / within bounds.
101
102
// This is a macro because we want the call-site line number for the ELOG.
103
#define PERFETTO_SVC_ERR(...) \
104
0
  (PERFETTO_ELOG(__VA_ARGS__), ::perfetto::base::ErrStatus(__VA_ARGS__))
105
106
namespace perfetto {
107
108
namespace {
109
constexpr int kMaxBuffersPerConsumer = 128;
110
constexpr uint32_t kDefaultSnapshotsIntervalMs = 10 * 1000;
111
constexpr int kDefaultWriteIntoFilePeriodMs = 5000;
112
constexpr int kMinWriteIntoFilePeriodMs = 100;
113
constexpr uint32_t kAllDataSourceStartedTimeout = 20000;
114
constexpr int kMaxConcurrentTracingSessions = 15;
115
constexpr int kMaxConcurrentTracingSessionsPerUid = 5;
116
constexpr int kMaxConcurrentTracingSessionsForStatsdUid = 10;
117
constexpr int64_t kMinSecondsBetweenTracesGuardrail = 5 * 60;
118
119
constexpr uint32_t kMillisPerHour = 3600000;
120
constexpr uint32_t kMillisPerDay = kMillisPerHour * 24;
121
constexpr uint32_t kMaxTracingDurationMillis = 7 * 24 * kMillisPerHour;
122
123
// These apply only if enable_extra_guardrails is true.
124
constexpr uint32_t kGuardrailsMaxTracingBufferSizeKb = 128 * 1024;
125
constexpr uint32_t kGuardrailsMaxTracingDurationMillis = 24 * kMillisPerHour;
126
127
constexpr size_t kMaxLifecycleEventsListedDataSources = 32;
128
129
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
130
struct iovec {
131
  void* iov_base;  // Address
132
  size_t iov_len;  // Block size
133
};
134
135
// Simple implementation of writev. Note that this does not give the atomicity
136
// guarantees of a real writev, but we don't depend on these (we aren't writing
137
// to the same file from another thread).
138
ssize_t writev(int fd, const struct iovec* iov, int iovcnt) {
139
  ssize_t total_size = 0;
140
  for (int i = 0; i < iovcnt; ++i) {
141
    ssize_t current_size = base::WriteAll(fd, iov[i].iov_base, iov[i].iov_len);
142
    if (current_size != static_cast<ssize_t>(iov[i].iov_len))
143
      return -1;
144
    total_size += current_size;
145
  }
146
  return total_size;
147
}
148
149
#define IOV_MAX 1024  // Linux compatible limit.
150
151
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_QNX)
152
#define IOV_MAX 1024  // Linux compatible limit.
153
#endif
154
155
// Partially encodes a CommitDataRequest in an int32 for the purposes of
156
// metatracing. Note that it encodes only the bottom 10 bits of the producer id
157
// (which is technically 16 bits wide).
158
//
159
// Format (by bit range):
160
// [   31 ][         30 ][             29:20 ][            19:10 ][        9:0]
161
// [unused][has flush id][num chunks to patch][num chunks to move][producer id]
162
int32_t EncodeCommitDataRequest(ProducerID producer_id,
163
0
                                const CommitDataRequest& req_untrusted) {
164
0
  uint32_t cmov = static_cast<uint32_t>(req_untrusted.chunks_to_move_size());
165
0
  uint32_t cpatch = static_cast<uint32_t>(req_untrusted.chunks_to_patch_size());
166
0
  uint32_t has_flush_id = req_untrusted.flush_request_id() != 0;
167
168
0
  uint32_t mask = (1 << 10) - 1;
169
0
  uint32_t acc = 0;
170
0
  acc |= has_flush_id << 30;
171
0
  acc |= (cpatch & mask) << 20;
172
0
  acc |= (cmov & mask) << 10;
173
0
  acc |= (producer_id & mask);
174
0
  return static_cast<int32_t>(acc);
175
0
}
176
177
void SerializeAndAppendPacket(std::vector<TracePacket>* packets,
178
2.70k
                              std::vector<uint8_t> packet) {
179
2.70k
  Slice slice = Slice::Allocate(packet.size());
180
2.70k
  memcpy(slice.own_data(), packet.data(), packet.size());
181
2.70k
  packets->emplace_back();
182
2.70k
  packets->back().AddSlice(std::move(slice));
183
2.70k
}
184
185
std::tuple<size_t /*shm_size*/, size_t /*page_size*/> EnsureValidShmSizes(
186
    size_t shm_size,
187
300
    size_t page_size) {
188
  // Theoretically the max page size supported by the ABI is 64KB.
189
  // However, the current implementation of TraceBuffer (the non-shared
190
  // userspace buffer where the service copies data) supports at most
191
  // 32K. Setting 64K "works" from the producer<>consumer viewpoint
192
  // but then causes the data to be discarded when copying it into
193
  // TraceBuffer.
194
300
  constexpr size_t kMaxPageSize = 32 * 1024;
195
300
  static_assert(kMaxPageSize <= SharedMemoryABI::kMaxPageSize, "");
196
197
300
  if (page_size == 0)
198
300
    page_size = TracingServiceImpl::kDefaultShmPageSize;
199
300
  if (shm_size == 0)
200
300
    shm_size = TracingServiceImpl::kDefaultShmSize;
201
202
300
  page_size = std::min<size_t>(page_size, kMaxPageSize);
203
300
  shm_size = std::min<size_t>(shm_size, TracingServiceImpl::kMaxShmSize);
204
205
  // The tracing page size has to be multiple of 4K. On some systems (e.g. Mac
206
  // on Arm64) the system page size can be larger (e.g., 16K). That doesn't
207
  // matter here, because the tracing page size is just a logical partitioning
208
  // and does not have any dependencies on kernel mm syscalls (read: it's fine
209
  // to have trace page sizes of 4K on a system where the kernel page size is
210
  // 16K).
211
300
  bool page_size_is_valid = page_size >= SharedMemoryABI::kMinPageSize;
212
300
  page_size_is_valid &= page_size % SharedMemoryABI::kMinPageSize == 0;
213
214
  // Only allow power of two numbers of pages, i.e. 1, 2, 4, 8 pages.
215
300
  size_t num_pages = page_size / SharedMemoryABI::kMinPageSize;
216
300
  page_size_is_valid &= (num_pages & (num_pages - 1)) == 0;
217
218
300
  if (!page_size_is_valid || shm_size < page_size ||
219
300
      shm_size % page_size != 0) {
220
0
    return std::make_tuple(TracingServiceImpl::kDefaultShmSize,
221
0
                           TracingServiceImpl::kDefaultShmPageSize);
222
0
  }
223
300
  return std::make_tuple(shm_size, page_size);
224
300
}
225
226
bool NameMatchesFilter(const std::string& name,
227
                       const std::vector<std::string>& name_filter,
228
300
                       const std::vector<std::string>& name_regex_filter) {
229
300
  bool filter_is_set = !name_filter.empty() || !name_regex_filter.empty();
230
300
  if (!filter_is_set)
231
300
    return true;
232
0
  bool filter_matches = std::find(name_filter.begin(), name_filter.end(),
233
0
                                  name) != name_filter.end();
234
0
  bool filter_regex_matches =
235
0
      std::find_if(name_regex_filter.begin(), name_regex_filter.end(),
236
0
                   [&](const std::string& regex) {
237
0
                     return std::regex_match(
238
0
                         name, std::regex(regex, std::regex::extended));
239
0
                   }) != name_regex_filter.end();
240
0
  return filter_matches || filter_regex_matches;
241
300
}
242
243
// Used when TraceConfig.write_into_file == true and output_path is not empty.
244
0
base::ScopedFile CreateTraceFile(const std::string& path, bool overwrite) {
245
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
246
    PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
247
  // This is NOT trying to preserve any security property, SELinux does that.
248
  // It just improves the actionability of the error when people try to save the
249
  // trace in a location that is not SELinux-allowed (a generic "permission
250
  // denied" vs "don't put it here, put it there").
251
  // These are the only SELinux approved dir for trace files that are created
252
  // directly by traced.
253
  static const char* kTraceDirBasePath = "/data/misc/perfetto-traces/";
254
  if (!base::StartsWith(path, kTraceDirBasePath)) {
255
    PERFETTO_ELOG("Invalid output_path %s. On Android it must be within %s.",
256
                  path.c_str(), kTraceDirBasePath);
257
    return base::ScopedFile();
258
  }
259
#endif
260
  // O_CREAT | O_EXCL will fail if the file exists already.
261
0
  const int flags = O_RDWR | O_CREAT | (overwrite ? O_TRUNC : O_EXCL);
262
0
  auto fd = base::OpenFile(path, flags, 0600);
263
0
  if (fd) {
264
0
#if defined(PERFETTO_HAS_CHMOD)
265
    // Passing 0644 directly above won't work because of umask.
266
0
    PERFETTO_CHECK(fchmod(*fd, 0644) == 0);
267
0
#endif
268
0
  } else {
269
0
    PERFETTO_PLOG("Failed to create %s", path.c_str());
270
0
  }
271
0
  return fd;
272
0
}
273
274
1.20k
bool ShouldLogEvent(const TraceConfig& cfg) {
275
1.20k
  switch (cfg.statsd_logging()) {
276
0
    case TraceConfig::STATSD_LOGGING_ENABLED:
277
0
      return true;
278
0
    case TraceConfig::STATSD_LOGGING_DISABLED:
279
0
      return false;
280
1.20k
    case TraceConfig::STATSD_LOGGING_UNSPECIFIED:
281
1.20k
      break;
282
1.20k
  }
283
  // For backward compatibility with older versions of perfetto_cmd.
284
1.20k
  return cfg.enable_extra_guardrails();
285
1.20k
}
286
287
// Appends `data` (which has `size` bytes), to `*packet`. Splits the data in
288
// slices no larger than `max_slice_size`.
289
void AppendOwnedSlicesToPacket(std::unique_ptr<uint8_t[]> data,
290
                               size_t size,
291
                               size_t max_slice_size,
292
0
                               perfetto::TracePacket* packet) {
293
0
  if (size <= max_slice_size) {
294
0
    packet->AddSlice(Slice::TakeOwnership(std::move(data), size));
295
0
    return;
296
0
  }
297
0
  uint8_t* src_ptr = data.get();
298
0
  for (size_t size_left = size; size_left > 0;) {
299
0
    const size_t slice_size = std::min(size_left, max_slice_size);
300
301
0
    Slice slice = Slice::Allocate(slice_size);
302
0
    memcpy(slice.own_data(), src_ptr, slice_size);
303
0
    packet->AddSlice(std::move(slice));
304
305
0
    src_ptr += slice_size;
306
0
    size_left -= slice_size;
307
0
  }
308
0
}
309
310
using TraceFilter = protos::gen::TraceConfig::TraceFilter;
311
std::optional<protozero::StringFilter::Policy> ConvertPolicy(
312
0
    TraceFilter::StringFilterPolicy policy) {
313
0
  switch (policy) {
314
0
    case TraceFilter::SFP_UNSPECIFIED:
315
0
      return std::nullopt;
316
0
    case TraceFilter::SFP_MATCH_REDACT_GROUPS:
317
0
      return protozero::StringFilter::Policy::kMatchRedactGroups;
318
0
    case TraceFilter::SFP_ATRACE_MATCH_REDACT_GROUPS:
319
0
      return protozero::StringFilter::Policy::kAtraceMatchRedactGroups;
320
0
    case TraceFilter::SFP_MATCH_BREAK:
321
0
      return protozero::StringFilter::Policy::kMatchBreak;
322
0
    case TraceFilter::SFP_ATRACE_MATCH_BREAK:
323
0
      return protozero::StringFilter::Policy::kAtraceMatchBreak;
324
0
    case TraceFilter::SFP_ATRACE_REPEATED_SEARCH_REDACT_GROUPS:
325
0
      return protozero::StringFilter::Policy::kAtraceRepeatedSearchRedactGroups;
326
0
  }
327
0
  return std::nullopt;
328
0
}
329
330
}  // namespace
331
332
// static
333
std::unique_ptr<TracingService> TracingService::CreateInstance(
334
    std::unique_ptr<SharedMemory::Factory> shm_factory,
335
    base::TaskRunner* task_runner,
336
311
    InitOpts init_opts) {
337
311
  tracing_service::Dependencies deps;
338
311
  deps.clock = std::make_unique<tracing_service::ClockImpl>();
339
311
  uint32_t seed = static_cast<uint32_t>(deps.clock->GetWallTimeMs().count());
340
311
  deps.random = std::make_unique<tracing_service::RandomImpl>(seed);
341
311
  return std::unique_ptr<TracingService>(new TracingServiceImpl(
342
311
      std::move(shm_factory), task_runner, std::move(deps), init_opts));
343
311
}
344
345
TracingServiceImpl::TracingServiceImpl(
346
    std::unique_ptr<SharedMemory::Factory> shm_factory,
347
    base::TaskRunner* task_runner,
348
    tracing_service::Dependencies deps,
349
    InitOpts init_opts)
350
311
    : clock_(std::move(deps.clock)),
351
311
      random_(std::move(deps.random)),
352
311
      init_opts_(init_opts),
353
311
      shm_factory_(std::move(shm_factory)),
354
311
      uid_(base::GetCurrentUserId()),
355
311
      buffer_ids_(kMaxTraceBufferID),
356
311
      weak_runner_(task_runner) {
357
311
  PERFETTO_DCHECK(task_runner);
358
311
}
359
360
311
TracingServiceImpl::~TracingServiceImpl() {
361
  // TODO(fmayer): handle teardown of all Producer.
362
311
}
363
364
std::unique_ptr<TracingService::ProducerEndpoint>
365
TracingServiceImpl::ConnectProducer(Producer* producer,
366
                                    const ClientIdentity& client_identity,
367
                                    const std::string& producer_name,
368
                                    size_t shared_memory_size_hint_bytes,
369
                                    bool in_process,
370
                                    ProducerSMBScrapingMode smb_scraping_mode,
371
                                    size_t shared_memory_page_size_hint_bytes,
372
                                    std::unique_ptr<SharedMemory> shm,
373
300
                                    const std::string& sdk_version) {
374
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
375
376
300
  auto uid = client_identity.uid();
377
300
  if (lockdown_mode_ && uid != base::GetCurrentUserId()) {
378
0
    PERFETTO_DLOG("Lockdown mode. Rejecting producer with UID %ld",
379
0
                  static_cast<unsigned long>(uid));
380
0
    return nullptr;
381
0
  }
382
383
300
  if (producers_.size() >= kMaxProducerID) {
384
0
    PERFETTO_DFATAL("Too many producers.");
385
0
    return nullptr;
386
0
  }
387
300
  const ProducerID id = GetNextProducerID();
388
300
  PERFETTO_DLOG("Producer %" PRIu16 " connected, uid=%d", id,
389
300
                static_cast<int>(uid));
390
300
  bool smb_scraping_enabled = smb_scraping_enabled_;
391
300
  switch (smb_scraping_mode) {
392
300
    case ProducerSMBScrapingMode::kDefault:
393
300
      break;
394
0
    case ProducerSMBScrapingMode::kEnabled:
395
0
      smb_scraping_enabled = true;
396
0
      break;
397
0
    case ProducerSMBScrapingMode::kDisabled:
398
0
      smb_scraping_enabled = false;
399
0
      break;
400
300
  }
401
402
300
  std::unique_ptr<ProducerEndpointImpl> endpoint(new ProducerEndpointImpl(
403
300
      id, client_identity, this, weak_runner_.task_runner(), producer,
404
300
      producer_name, sdk_version, in_process, smb_scraping_enabled));
405
300
  auto it_and_inserted = producers_.emplace(id, endpoint.get());
406
300
  PERFETTO_DCHECK(it_and_inserted.second);
407
300
  endpoint->shmem_size_hint_bytes_ = shared_memory_size_hint_bytes;
408
300
  endpoint->shmem_page_size_hint_bytes_ = shared_memory_page_size_hint_bytes;
409
410
  // Producer::OnConnect() should run before Producer::OnTracingSetup(). The
411
  // latter may be posted by SetupSharedMemory() below, so post OnConnect() now.
412
300
  endpoint->weak_runner_.PostTask(
413
300
      [endpoint = endpoint.get()] { endpoint->producer_->OnConnect(); });
414
415
300
  if (shm) {
416
    // The producer supplied an SMB. This is used only by Chrome; in the most
417
    // common cases the SMB is created by the service and passed via
418
    // OnTracingSetup(). Verify that it is correctly sized before we attempt to
419
    // use it. The transport layer has to verify the integrity of the SMB (e.g.
420
    // ensure that the producer can't resize if after the fact).
421
0
    size_t shm_size, page_size;
422
0
    std::tie(shm_size, page_size) =
423
0
        EnsureValidShmSizes(shm->size(), endpoint->shmem_page_size_hint_bytes_);
424
0
    if (shm_size == shm->size() &&
425
0
        page_size == endpoint->shmem_page_size_hint_bytes_) {
426
0
      PERFETTO_DLOG(
427
0
          "Adopting producer-provided SMB of %zu kB for producer \"%s\"",
428
0
          shm_size / 1024, endpoint->name_.c_str());
429
0
      endpoint->SetupSharedMemory(std::move(shm), page_size,
430
0
                                  /*provided_by_producer=*/true);
431
0
    } else {
432
0
      PERFETTO_LOG(
433
0
          "Discarding incorrectly sized producer-provided SMB for producer "
434
0
          "\"%s\", falling back to service-provided SMB. Requested sizes: %zu "
435
0
          "B total, %zu B page size; suggested corrected sizes: %zu B total, "
436
0
          "%zu B page size",
437
0
          endpoint->name_.c_str(), shm->size(),
438
0
          endpoint->shmem_page_size_hint_bytes_, shm_size, page_size);
439
0
      shm.reset();
440
0
    }
441
0
  }
442
443
300
  return std::unique_ptr<ProducerEndpoint>(std::move(endpoint));
444
300
}
445
446
300
void TracingServiceImpl::DisconnectProducer(ProducerID id) {
447
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
448
300
  PERFETTO_DLOG("Producer %" PRIu16 " disconnected", id);
449
300
  PERFETTO_DCHECK(producers_.count(id));
450
451
  // Scrape remaining chunks for this producer to ensure we don't lose data.
452
300
  if (auto* producer = GetProducer(id)) {
453
300
    for (auto& session_id_and_session : tracing_sessions_)
454
300
      ScrapeSharedMemoryBuffers(&session_id_and_session.second, producer);
455
300
  }
456
457
600
  for (auto it = data_sources_.begin(); it != data_sources_.end();) {
458
300
    auto next = it;
459
300
    next++;
460
300
    if (it->second.producer_id == id)
461
300
      UnregisterDataSource(id, it->second.descriptor.name());
462
300
    it = next;
463
300
  }
464
465
300
  producers_.erase(id);
466
300
  UpdateMemoryGuardrail();
467
300
}
468
469
TracingServiceImpl::ProducerEndpointImpl* TracingServiceImpl::GetProducer(
470
45.9k
    ProducerID id) const {
471
45.9k
  PERFETTO_DCHECK_THREAD(thread_checker_);
472
45.9k
  auto it = producers_.find(id);
473
45.9k
  if (it == producers_.end())
474
0
    return nullptr;
475
45.9k
  return it->second;
476
45.9k
}
477
478
std::unique_ptr<TracingService::ConsumerEndpoint>
479
300
TracingServiceImpl::ConnectConsumer(Consumer* consumer, uid_t uid) {
480
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
481
300
  PERFETTO_DLOG("Consumer %p connected from UID %" PRIu64,
482
300
                reinterpret_cast<void*>(consumer), static_cast<uint64_t>(uid));
483
300
  std::unique_ptr<ConsumerEndpointImpl> endpoint(new ConsumerEndpointImpl(
484
300
      this, weak_runner_.task_runner(), consumer, uid));
485
  // Consumer might go away before we're able to send the connect notification,
486
  // if that is the case just bail out.
487
300
  auto weak_ptr = endpoint->weak_ptr_factory_.GetWeakPtr();
488
300
  weak_runner_.task_runner()->PostTask([weak_ptr = std::move(weak_ptr)] {
489
300
    if (weak_ptr)
490
300
      weak_ptr->consumer_->OnConnect();
491
300
  });
492
300
  return std::unique_ptr<ConsumerEndpoint>(std::move(endpoint));
493
300
}
494
495
300
void TracingServiceImpl::DisconnectConsumer(ConsumerEndpointImpl* consumer) {
496
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
497
300
  PERFETTO_DLOG("Consumer %p disconnected", reinterpret_cast<void*>(consumer));
498
499
300
  if (consumer->tracing_session_id_)
500
300
    FreeBuffers(consumer->tracing_session_id_);  // Will also DisableTracing().
501
502
  // At this point no more pointers to |consumer| should be around.
503
300
  PERFETTO_DCHECK(!std::any_of(
504
300
      tracing_sessions_.begin(), tracing_sessions_.end(),
505
300
      [consumer](const std::pair<const TracingSessionID, TracingSession>& kv) {
506
300
        return kv.second.consumer_maybe_null == consumer;
507
300
      }));
508
300
}
509
510
bool TracingServiceImpl::DetachConsumer(ConsumerEndpointImpl* consumer,
511
0
                                        const std::string& key) {
512
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
513
0
  PERFETTO_DLOG("Consumer %p detached", reinterpret_cast<void*>(consumer));
514
515
0
  TracingSessionID tsid = consumer->tracing_session_id_;
516
0
  TracingSession* tracing_session;
517
0
  if (!tsid || !(tracing_session = GetTracingSession(tsid)))
518
0
    return false;
519
520
0
  if (GetDetachedSession(consumer->uid_, key)) {
521
0
    PERFETTO_ELOG("Another session has been detached with the same key \"%s\"",
522
0
                  key.c_str());
523
0
    return false;
524
0
  }
525
526
0
  PERFETTO_DCHECK(tracing_session->consumer_maybe_null == consumer);
527
0
  tracing_session->consumer_maybe_null = nullptr;
528
0
  tracing_session->detach_key = key;
529
0
  consumer->tracing_session_id_ = 0;
530
0
  return true;
531
0
}
532
533
std::unique_ptr<TracingService::RelayEndpoint>
534
0
TracingServiceImpl::ConnectRelayClient(RelayClientID relay_client_id) {
535
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
536
537
0
  auto endpoint = std::make_unique<RelayEndpointImpl>(relay_client_id, this);
538
0
  relay_clients_[relay_client_id] = endpoint.get();
539
540
0
  return std::move(endpoint);
541
0
}
542
543
0
void TracingServiceImpl::DisconnectRelayClient(RelayClientID relay_client_id) {
544
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
545
546
0
  if (relay_clients_.find(relay_client_id) == relay_clients_.end())
547
0
    return;
548
0
  relay_clients_.erase(relay_client_id);
549
0
}
550
551
bool TracingServiceImpl::AttachConsumer(ConsumerEndpointImpl* consumer,
552
0
                                        const std::string& key) {
553
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
554
0
  PERFETTO_DLOG("Consumer %p attaching to session %s",
555
0
                reinterpret_cast<void*>(consumer), key.c_str());
556
557
0
  if (consumer->tracing_session_id_) {
558
0
    PERFETTO_ELOG(
559
0
        "Cannot reattach consumer to session %s"
560
0
        " while it already attached tracing session ID %" PRIu64,
561
0
        key.c_str(), consumer->tracing_session_id_);
562
0
    return false;
563
0
  }
564
565
0
  auto* tracing_session = GetDetachedSession(consumer->uid_, key);
566
0
  if (!tracing_session) {
567
0
    PERFETTO_ELOG(
568
0
        "Failed to attach consumer, session '%s' not found for uid %d",
569
0
        key.c_str(), static_cast<int>(consumer->uid_));
570
0
    return false;
571
0
  }
572
573
0
  consumer->tracing_session_id_ = tracing_session->id;
574
0
  tracing_session->consumer_maybe_null = consumer;
575
0
  tracing_session->detach_key.clear();
576
0
  return true;
577
0
}
578
579
base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
580
                                               const TraceConfig& cfg,
581
300
                                               base::ScopedFile fd) {
582
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
583
584
  // If the producer is specifying a UUID, respect that (at least for the first
585
  // snapshot). Otherwise generate a new UUID.
586
300
  base::Uuid uuid(cfg.trace_uuid_lsb(), cfg.trace_uuid_msb());
587
300
  if (!uuid)
588
300
    uuid = base::Uuidv4();
589
590
300
  PERFETTO_DLOG("Enabling tracing for consumer %p, UUID: %s",
591
300
                reinterpret_cast<void*>(consumer),
592
300
                uuid.ToPrettyString().c_str());
593
300
  MaybeLogUploadEvent(cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracing);
594
300
  if (cfg.lockdown_mode() == TraceConfig::LOCKDOWN_SET)
595
0
    lockdown_mode_ = true;
596
300
  if (cfg.lockdown_mode() == TraceConfig::LOCKDOWN_CLEAR)
597
0
    lockdown_mode_ = false;
598
599
  // Scope |tracing_session| to this block to prevent accidental use of a null
600
  // pointer later in this function.
601
300
  {
602
300
    TracingSession* tracing_session =
603
300
        GetTracingSession(consumer->tracing_session_id_);
604
300
    if (tracing_session) {
605
0
      MaybeLogUploadEvent(
606
0
          cfg, uuid,
607
0
          PerfettoStatsdAtom::kTracedEnableTracingExistingTraceSession);
608
0
      return PERFETTO_SVC_ERR(
609
0
          "A Consumer is trying to EnableTracing() but another tracing "
610
0
          "session is already active (forgot a call to FreeBuffers() ?)");
611
0
    }
612
300
  }
613
614
300
  const uint32_t max_duration_ms = cfg.enable_extra_guardrails()
615
300
                                       ? kGuardrailsMaxTracingDurationMillis
616
300
                                       : kMaxTracingDurationMillis;
617
300
  if (cfg.duration_ms() > max_duration_ms) {
618
0
    MaybeLogUploadEvent(cfg, uuid,
619
0
                        PerfettoStatsdAtom::kTracedEnableTracingTooLongTrace);
620
0
    return PERFETTO_SVC_ERR("Requested too long trace (%" PRIu32
621
0
                            "ms  > %" PRIu32 " ms)",
622
0
                            cfg.duration_ms(), max_duration_ms);
623
0
  }
624
625
300
  const bool has_trigger_config =
626
300
      GetTriggerMode(cfg) != TraceConfig::TriggerConfig::UNSPECIFIED;
627
300
  if (has_trigger_config &&
628
0
      (cfg.trigger_config().trigger_timeout_ms() == 0 ||
629
0
       cfg.trigger_config().trigger_timeout_ms() > max_duration_ms)) {
630
0
    MaybeLogUploadEvent(
631
0
        cfg, uuid,
632
0
        PerfettoStatsdAtom::kTracedEnableTracingInvalidTriggerTimeout);
633
0
    return PERFETTO_SVC_ERR(
634
0
        "Traces with START_TRACING triggers must provide a positive "
635
0
        "trigger_timeout_ms < 7 days (received %" PRIu32 "ms)",
636
0
        cfg.trigger_config().trigger_timeout_ms());
637
0
  }
638
639
  // This check has been introduced in May 2023 after finding b/274931668.
640
300
  if (static_cast<int>(cfg.trigger_config().trigger_mode()) >
641
300
      TraceConfig::TriggerConfig::TriggerMode_MAX) {
642
0
    MaybeLogUploadEvent(
643
0
        cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidTriggerMode);
644
0
    return PERFETTO_SVC_ERR(
645
0
        "The trace config specified an invalid trigger_mode");
646
0
  }
647
648
300
  if (cfg.trigger_config().use_clone_snapshot_if_available() &&
649
0
      cfg.trigger_config().trigger_mode() !=
650
0
          TraceConfig::TriggerConfig::STOP_TRACING) {
651
0
    MaybeLogUploadEvent(
652
0
        cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidTriggerMode);
653
0
    return PERFETTO_SVC_ERR(
654
0
        "trigger_mode must be STOP_TRACING when "
655
0
        "use_clone_snapshot_if_available=true");
656
0
  }
657
658
300
  if (has_trigger_config && cfg.duration_ms() != 0) {
659
0
    MaybeLogUploadEvent(
660
0
        cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingDurationWithTrigger);
661
0
    return PERFETTO_SVC_ERR(
662
0
        "duration_ms was set, this must not be set for traces with triggers.");
663
0
  }
664
665
300
  for (char c : cfg.bugreport_filename()) {
666
0
    if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
667
0
          (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.')) {
668
0
      MaybeLogUploadEvent(
669
0
          cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidBrFilename);
670
0
      return PERFETTO_SVC_ERR(
671
0
          "bugreport_filename contains invalid chars. Use [a-zA-Z0-9-_.]+");
672
0
    }
673
0
  }
674
675
300
  if ((GetTriggerMode(cfg) == TraceConfig::TriggerConfig::STOP_TRACING ||
676
300
       GetTriggerMode(cfg) == TraceConfig::TriggerConfig::CLONE_SNAPSHOT) &&
677
0
      cfg.write_into_file()) {
678
    // We don't support this usecase because there are subtle assumptions which
679
    // break around TracingServiceEvents and windowed sorting (i.e. if we don't
680
    // drain the events in ReadBuffersIntoFile because we are waiting for
681
    // STOP_TRACING, we can end up queueing up a lot of TracingServiceEvents and
682
    // emitting them wildy out of order breaking windowed sorting in trace
683
    // processor).
684
0
    MaybeLogUploadEvent(
685
0
        cfg, uuid,
686
0
        PerfettoStatsdAtom::kTracedEnableTracingStopTracingWriteIntoFile);
687
0
    return PERFETTO_SVC_ERR(
688
0
        "Specifying trigger mode STOP_TRACING/CLONE_SNAPSHOT and "
689
0
        "write_into_file together is unsupported");
690
0
  }
691
692
300
  std::unordered_set<std::string> triggers;
693
300
  for (const auto& trigger : cfg.trigger_config().triggers()) {
694
0
    if (!triggers.insert(trigger.name()).second) {
695
0
      MaybeLogUploadEvent(
696
0
          cfg, uuid,
697
0
          PerfettoStatsdAtom::kTracedEnableTracingDuplicateTriggerName);
698
0
      return PERFETTO_SVC_ERR("Duplicate trigger name: %s",
699
0
                              trigger.name().c_str());
700
0
    }
701
0
  }
702
703
300
  if (cfg.enable_extra_guardrails()) {
704
0
    if (cfg.deferred_start()) {
705
0
      MaybeLogUploadEvent(
706
0
          cfg, uuid,
707
0
          PerfettoStatsdAtom::kTracedEnableTracingInvalidDeferredStart);
708
0
      return PERFETTO_SVC_ERR(
709
0
          "deferred_start=true is not supported in unsupervised traces");
710
0
    }
711
0
    uint64_t buf_size_sum = 0;
712
0
    for (const auto& buf : cfg.buffers()) {
713
0
      if (buf.size_kb() % 4 != 0) {
714
0
        MaybeLogUploadEvent(
715
0
            cfg, uuid,
716
0
            PerfettoStatsdAtom::kTracedEnableTracingInvalidBufferSize);
717
0
        return PERFETTO_SVC_ERR(
718
0
            "buffers.size_kb must be a multiple of 4, got %" PRIu32,
719
0
            buf.size_kb());
720
0
      }
721
0
      buf_size_sum += buf.size_kb();
722
0
    }
723
724
0
    uint32_t max_tracing_buffer_size_kb =
725
0
        std::max(kGuardrailsMaxTracingBufferSizeKb,
726
0
                 cfg.guardrail_overrides().max_tracing_buffer_size_kb());
727
0
    if (buf_size_sum > max_tracing_buffer_size_kb) {
728
0
      MaybeLogUploadEvent(
729
0
          cfg, uuid,
730
0
          PerfettoStatsdAtom::kTracedEnableTracingBufferSizeTooLarge);
731
0
      return PERFETTO_SVC_ERR("Requested too large trace buffer (%" PRIu64
732
0
                              "kB  > %" PRIu32 " kB)",
733
0
                              buf_size_sum, max_tracing_buffer_size_kb);
734
0
    }
735
0
  }
736
737
300
  if (cfg.buffers_size() > kMaxBuffersPerConsumer) {
738
0
    MaybeLogUploadEvent(cfg, uuid,
739
0
                        PerfettoStatsdAtom::kTracedEnableTracingTooManyBuffers);
740
0
    return PERFETTO_SVC_ERR("Too many buffers configured (%d)",
741
0
                            cfg.buffers_size());
742
0
  }
743
  // Check that the config specifies all buffers for its data sources. This
744
  // is also checked in SetupDataSource, but it is simpler to return a proper
745
  // error to the consumer from here (and there will be less state to undo).
746
300
  for (const TraceConfig::DataSource& cfg_data_source : cfg.data_sources()) {
747
300
    size_t num_buffers = static_cast<size_t>(cfg.buffers_size());
748
300
    size_t target_buffer = cfg_data_source.config().target_buffer();
749
300
    if (target_buffer >= num_buffers) {
750
0
      MaybeLogUploadEvent(
751
0
          cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingOobTargetBuffer);
752
0
      return PERFETTO_SVC_ERR(
753
0
          "Data source \"%s\" specified an out of bounds target_buffer (%zu >= "
754
0
          "%zu)",
755
0
          cfg_data_source.config().name().c_str(), target_buffer, num_buffers);
756
0
    }
757
300
  }
758
759
300
  if (!cfg.unique_session_name().empty()) {
760
0
    const std::string& name = cfg.unique_session_name();
761
0
    for (auto& kv : tracing_sessions_) {
762
0
      if (kv.second.state == TracingSession::CLONED_READ_ONLY)
763
0
        continue;  // Don't consider cloned sessions in uniqueness checks.
764
0
      if (kv.second.config.unique_session_name() == name) {
765
0
        MaybeLogUploadEvent(
766
0
            cfg, uuid,
767
0
            PerfettoStatsdAtom::kTracedEnableTracingDuplicateSessionName);
768
0
        static const char fmt[] =
769
0
            "A trace with this unique session name (%s) already exists";
770
        // This happens frequently, don't make it an "E"LOG.
771
0
        PERFETTO_LOG(fmt, name.c_str());
772
0
        return base::ErrStatus(fmt, name.c_str());
773
0
      }
774
0
    }
775
0
  }
776
777
300
  if (!cfg.session_semaphores().empty()) {
778
0
    struct SemaphoreSessionsState {
779
0
      uint64_t smallest_max_other_session_count =
780
0
          std::numeric_limits<uint64_t>::max();
781
0
      uint64_t session_count = 0;
782
0
    };
783
    // For each semaphore, compute the number of active sessions and the
784
    // MIN(limit).
785
0
    std::unordered_map<std::string, SemaphoreSessionsState>
786
0
        sem_to_sessions_state;
787
0
    for (const auto& id_and_session : tracing_sessions_) {
788
0
      const auto& session = id_and_session.second;
789
0
      if (session.state == TracingSession::CLONED_READ_ONLY ||
790
0
          session.state == TracingSession::DISABLED) {
791
        // Don't consider cloned or disabled sessions in checks.
792
0
        continue;
793
0
      }
794
0
      for (const auto& sem : session.config.session_semaphores()) {
795
0
        auto& sessions_state = sem_to_sessions_state[sem.name()];
796
0
        sessions_state.smallest_max_other_session_count =
797
0
            std::min(sessions_state.smallest_max_other_session_count,
798
0
                     sem.max_other_session_count());
799
0
        sessions_state.session_count++;
800
0
      }
801
0
    }
802
803
    // Check if any of the semaphores declared by the config clashes with any of
804
    // the currently active semaphores.
805
0
    for (const auto& semaphore : cfg.session_semaphores()) {
806
0
      auto it = sem_to_sessions_state.find(semaphore.name());
807
0
      if (it == sem_to_sessions_state.end()) {
808
0
        continue;
809
0
      }
810
0
      uint64_t max_other_session_count =
811
0
          std::min(semaphore.max_other_session_count(),
812
0
                   it->second.smallest_max_other_session_count);
813
0
      if (it->second.session_count > max_other_session_count) {
814
0
        MaybeLogUploadEvent(
815
0
            cfg, uuid,
816
0
            PerfettoStatsdAtom::
817
0
                kTracedEnableTracingFailedSessionSemaphoreCheck);
818
0
        return PERFETTO_SVC_ERR(
819
0
            "Semaphore \"%s\" exceeds maximum allowed other session count "
820
0
            "(%" PRIu64 " > min(%" PRIu64 ", %" PRIu64 "))",
821
0
            semaphore.name().c_str(), it->second.session_count,
822
0
            semaphore.max_other_session_count(),
823
0
            it->second.smallest_max_other_session_count);
824
0
      }
825
0
    }
826
0
  }
827
828
300
  if (cfg.enable_extra_guardrails()) {
829
    // unique_session_name can be empty
830
0
    const std::string& name = cfg.unique_session_name();
831
0
    int64_t now_s = clock_->GetBootTimeS().count();
832
833
    // Remove any entries where the time limit has passed so this map doesn't
834
    // grow indefinitely:
835
0
    std::map<std::string, int64_t>& sessions = session_to_last_trace_s_;
836
0
    for (auto it = sessions.cbegin(); it != sessions.cend();) {
837
0
      if (now_s - it->second > kMinSecondsBetweenTracesGuardrail) {
838
0
        it = sessions.erase(it);
839
0
      } else {
840
0
        ++it;
841
0
      }
842
0
    }
843
844
0
    int64_t& previous_s = session_to_last_trace_s_[name];
845
0
    if (previous_s == 0) {
846
0
      previous_s = now_s;
847
0
    } else {
848
0
      MaybeLogUploadEvent(
849
0
          cfg, uuid,
850
0
          PerfettoStatsdAtom::kTracedEnableTracingSessionNameTooRecent);
851
0
      return PERFETTO_SVC_ERR(
852
0
          "A trace with unique session name \"%s\" began less than %" PRId64
853
0
          "s ago (%" PRId64 "s)",
854
0
          name.c_str(), kMinSecondsBetweenTracesGuardrail, now_s - previous_s);
855
0
    }
856
0
  }
857
858
300
  const int sessions_for_uid = static_cast<int>(std::count_if(
859
300
      tracing_sessions_.begin(), tracing_sessions_.end(),
860
300
      [consumer](const decltype(tracing_sessions_)::value_type& s) {
861
0
        return s.second.consumer_uid == consumer->uid_;
862
0
      }));
863
864
300
  int per_uid_limit = kMaxConcurrentTracingSessionsPerUid;
865
300
  if (consumer->uid_ == 1066 /* AID_STATSD*/) {
866
0
    per_uid_limit = kMaxConcurrentTracingSessionsForStatsdUid;
867
0
  }
868
300
  if (sessions_for_uid >= per_uid_limit) {
869
0
    MaybeLogUploadEvent(
870
0
        cfg, uuid,
871
0
        PerfettoStatsdAtom::kTracedEnableTracingTooManySessionsForUid);
872
0
    return PERFETTO_SVC_ERR(
873
0
        "Too many concurrent tracing sesions (%d) for uid %d limit is %d",
874
0
        sessions_for_uid, static_cast<int>(consumer->uid_), per_uid_limit);
875
0
  }
876
877
  // TODO(primiano): This is a workaround to prevent that a producer gets stuck
878
  // in a state where it stalls by design by having more TraceWriterImpl
879
  // instances than free pages in the buffer. This is really a bug in
880
  // trace_probes and the way it handles stalls in the shmem buffer.
881
300
  if (tracing_sessions_.size() >= kMaxConcurrentTracingSessions) {
882
0
    MaybeLogUploadEvent(
883
0
        cfg, uuid,
884
0
        PerfettoStatsdAtom::kTracedEnableTracingTooManyConcurrentSessions);
885
0
    return PERFETTO_SVC_ERR("Too many concurrent tracing sesions (%zu)",
886
0
                            tracing_sessions_.size());
887
0
  }
888
889
  // If the trace config provides a filter bytecode, setup the filter now.
890
  // If the filter loading fails, abort the tracing session rather than running
891
  // unfiltered.
892
300
  std::unique_ptr<protozero::MessageFilter> trace_filter;
893
300
  if (cfg.has_trace_filter()) {
894
0
    const auto& filt = cfg.trace_filter();
895
0
    trace_filter.reset(new protozero::MessageFilter());
896
897
0
    protozero::StringFilter& string_filter = trace_filter->string_filter();
898
0
    for (const auto& rule : filt.string_filter_chain().rules()) {
899
0
      auto opt_policy = ConvertPolicy(rule.policy());
900
0
      if (!opt_policy.has_value()) {
901
0
        MaybeLogUploadEvent(
902
0
            cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidFilter);
903
0
        return PERFETTO_SVC_ERR(
904
0
            "Trace filter has invalid string filtering rules, aborting");
905
0
      }
906
0
      string_filter.AddRule(*opt_policy, rule.regex_pattern(),
907
0
                            rule.atrace_payload_starts_with());
908
0
    }
909
910
0
    const std::string& bytecode_v1 = filt.bytecode();
911
0
    const std::string& bytecode_v2 = filt.bytecode_v2();
912
0
    const std::string& bytecode =
913
0
        bytecode_v2.empty() ? bytecode_v1 : bytecode_v2;
914
0
    if (!trace_filter->LoadFilterBytecode(bytecode.data(), bytecode.size())) {
915
0
      MaybeLogUploadEvent(
916
0
          cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidFilter);
917
0
      return PERFETTO_SVC_ERR("Trace filter bytecode invalid, aborting");
918
0
    }
919
920
    // The filter is created using perfetto.protos.Trace as root message
921
    // (because that makes it possible to play around with the `proto_filter`
922
    // tool on actual traces). Here in the service, however, we deal with
923
    // perfetto.protos.TracePacket(s), which are one level down (Trace.packet).
924
    // The IPC client (or the write_into_filte logic in here) are responsible
925
    // for pre-pending the packet preamble (See GetProtoPreamble() calls), but
926
    // the preamble is not there at ReadBuffer time. Hence we change the root of
927
    // the filtering to start at the Trace.packet level.
928
0
    if (!trace_filter->SetFilterRoot({TracePacket::kPacketFieldNumber})) {
929
0
      MaybeLogUploadEvent(
930
0
          cfg, uuid, PerfettoStatsdAtom::kTracedEnableTracingInvalidFilter);
931
0
      return PERFETTO_SVC_ERR("Failed to set filter root.");
932
0
    }
933
0
  }
934
935
300
  const TracingSessionID tsid = ++last_tracing_session_id_;
936
300
  TracingSession* tracing_session =
937
300
      &tracing_sessions_
938
300
           .emplace(std::piecewise_construct, std::forward_as_tuple(tsid),
939
300
                    std::forward_as_tuple(tsid, consumer, cfg,
940
300
                                          weak_runner_.task_runner()))
941
300
           .first->second;
942
943
300
  tracing_session->trace_uuid = uuid;
944
945
300
  if (trace_filter)
946
0
    tracing_session->trace_filter = std::move(trace_filter);
947
948
300
  if (cfg.write_into_file()) {
949
0
    if (!fd ^ !cfg.output_path().empty()) {
950
0
      MaybeLogUploadEvent(
951
0
          tracing_session->config, uuid,
952
0
          PerfettoStatsdAtom::kTracedEnableTracingInvalidFdOutputFile);
953
0
      tracing_sessions_.erase(tsid);
954
0
      return PERFETTO_SVC_ERR(
955
0
          "When write_into_file==true either a FD needs to be passed or "
956
0
          "output_path must be populated (but not both)");
957
0
    }
958
0
    if (!cfg.output_path().empty()) {
959
0
      fd = CreateTraceFile(cfg.output_path(), /*overwrite=*/false);
960
0
      if (!fd) {
961
0
        MaybeLogUploadEvent(
962
0
            tracing_session->config, uuid,
963
0
            PerfettoStatsdAtom::kTracedEnableTracingFailedToCreateFile);
964
0
        tracing_sessions_.erase(tsid);
965
0
        return PERFETTO_SVC_ERR("Failed to create the trace file %s",
966
0
                                cfg.output_path().c_str());
967
0
      }
968
0
    }
969
0
    tracing_session->write_into_file = std::move(fd);
970
0
    uint32_t write_period_ms = cfg.file_write_period_ms();
971
0
    if (write_period_ms == 0)
972
0
      write_period_ms = kDefaultWriteIntoFilePeriodMs;
973
0
    if (write_period_ms < kMinWriteIntoFilePeriodMs)
974
0
      write_period_ms = kMinWriteIntoFilePeriodMs;
975
0
    tracing_session->write_period_ms = write_period_ms;
976
0
    tracing_session->max_file_size_bytes = cfg.max_file_size_bytes();
977
0
    tracing_session->bytes_written_into_file = 0;
978
0
  }
979
980
300
  if (cfg.compression_type() == TraceConfig::COMPRESSION_TYPE_DEFLATE) {
981
0
    if (init_opts_.compressor_fn) {
982
0
      tracing_session->compress_deflate = true;
983
0
    } else {
984
0
      PERFETTO_LOG(
985
0
          "COMPRESSION_TYPE_DEFLATE is not supported in the current build "
986
0
          "configuration. Skipping compression");
987
0
    }
988
0
  }
989
990
  // Initialize the log buffers.
991
300
  bool did_allocate_all_buffers = true;
992
300
  bool invalid_buffer_config = false;
993
994
  // Allocate the trace buffers. Also create a map to translate a consumer
995
  // relative index (TraceConfig.DataSourceConfig.target_buffer) into the
996
  // corresponding BufferID, which is a global ID namespace for the service and
997
  // all producers.
998
300
  size_t total_buf_size_kb = 0;
999
300
  const size_t num_buffers = static_cast<size_t>(cfg.buffers_size());
1000
300
  tracing_session->buffers_index.reserve(num_buffers);
1001
600
  for (size_t i = 0; i < num_buffers; i++) {
1002
300
    const TraceConfig::BufferConfig& buffer_cfg = cfg.buffers()[i];
1003
300
    BufferID global_id = buffer_ids_.Allocate();
1004
300
    if (!global_id) {
1005
0
      did_allocate_all_buffers = false;  // We ran out of IDs.
1006
0
      break;
1007
0
    }
1008
300
    tracing_session->buffers_index.push_back(global_id);
1009
    // TraceBuffer size is limited to 32-bit.
1010
300
    const uint32_t buf_size_kb = buffer_cfg.size_kb();
1011
300
    const uint64_t buf_size_bytes = buf_size_kb * static_cast<uint64_t>(1024);
1012
300
    const size_t buf_size = static_cast<size_t>(buf_size_bytes);
1013
300
    if (buf_size_bytes == 0 ||
1014
300
        buf_size_bytes > std::numeric_limits<uint32_t>::max() ||
1015
300
        buf_size != buf_size_bytes) {
1016
0
      invalid_buffer_config = true;
1017
0
      did_allocate_all_buffers = false;
1018
0
      break;
1019
0
    }
1020
300
    total_buf_size_kb += buf_size_kb;
1021
300
    TraceBuffer::OverwritePolicy policy =
1022
300
        buffer_cfg.fill_policy() == TraceConfig::BufferConfig::DISCARD
1023
300
            ? TraceBuffer::kDiscard
1024
300
            : TraceBuffer::kOverwrite;
1025
300
    auto it_and_inserted =
1026
300
        buffers_.emplace(global_id, TraceBuffer::Create(buf_size, policy));
1027
300
    PERFETTO_DCHECK(it_and_inserted.second);  // buffers_.count(global_id) == 0.
1028
300
    std::unique_ptr<TraceBuffer>& trace_buffer = it_and_inserted.first->second;
1029
300
    if (!trace_buffer) {
1030
0
      did_allocate_all_buffers = false;
1031
0
      break;
1032
0
    }
1033
300
  }
1034
1035
  // This can happen if either:
1036
  // - All the kMaxTraceBufferID slots are taken.
1037
  // - OOM, or, more realistically, we exhausted virtual memory.
1038
  // - The buffer size in the config is invalid.
1039
  // In any case, free all the previously allocated buffers and abort.
1040
300
  if (!did_allocate_all_buffers) {
1041
0
    for (BufferID global_id : tracing_session->buffers_index) {
1042
0
      buffer_ids_.Free(global_id);
1043
0
      buffers_.erase(global_id);
1044
0
    }
1045
0
    MaybeLogUploadEvent(tracing_session->config, uuid,
1046
0
                        PerfettoStatsdAtom::kTracedEnableTracingOom);
1047
0
    tracing_sessions_.erase(tsid);
1048
0
    if (invalid_buffer_config) {
1049
0
      return PERFETTO_SVC_ERR(
1050
0
          "Failed to allocate tracing buffers: Invalid buffer sizes");
1051
0
    }
1052
0
    return PERFETTO_SVC_ERR(
1053
0
        "Failed to allocate tracing buffers: OOM or too many buffers");
1054
0
  }
1055
1056
300
  UpdateMemoryGuardrail();
1057
1058
300
  consumer->tracing_session_id_ = tsid;
1059
1060
  // Setup the data sources on the producers without starting them.
1061
300
  for (const TraceConfig::DataSource& cfg_data_source : cfg.data_sources()) {
1062
    // Scan all the registered data sources with a matching name.
1063
300
    auto range = data_sources_.equal_range(cfg_data_source.config().name());
1064
387
    for (auto it = range.first; it != range.second; it++) {
1065
87
      TraceConfig::ProducerConfig producer_config;
1066
87
      for (const auto& config : cfg.producers()) {
1067
0
        if (GetProducer(it->second.producer_id)->name_ ==
1068
0
            config.producer_name()) {
1069
0
          producer_config = config;
1070
0
          break;
1071
0
        }
1072
0
      }
1073
87
      SetupDataSource(cfg_data_source, producer_config, it->second,
1074
87
                      tracing_session);
1075
87
    }
1076
300
  }
1077
1078
300
  bool has_start_trigger = false;
1079
300
  switch (GetTriggerMode(cfg)) {
1080
300
    case TraceConfig::TriggerConfig::UNSPECIFIED:
1081
      // no triggers are specified so this isn't a trace that is using triggers.
1082
300
      PERFETTO_DCHECK(!has_trigger_config);
1083
300
      break;
1084
0
    case TraceConfig::TriggerConfig::START_TRACING:
1085
      // For traces which use START_TRACE triggers we need to ensure that the
1086
      // tracing session will be cleaned up when it times out.
1087
0
      has_start_trigger = true;
1088
0
      weak_runner_.PostDelayedTask(
1089
0
          [tsid, this]() { OnStartTriggersTimeout(tsid); },
1090
0
          cfg.trigger_config().trigger_timeout_ms());
1091
0
      break;
1092
0
    case TraceConfig::TriggerConfig::STOP_TRACING:
1093
0
    case TraceConfig::TriggerConfig::CLONE_SNAPSHOT:
1094
      // Update the tracing_session's duration_ms to ensure that if no trigger
1095
      // is received the session will end and be cleaned up equal to the
1096
      // timeout.
1097
      //
1098
      // TODO(nuskos): Refactor this so that rather then modifying the config we
1099
      // have a field we look at on the tracing_session.
1100
0
      tracing_session->config.set_duration_ms(
1101
0
          cfg.trigger_config().trigger_timeout_ms());
1102
0
      break;
1103
1104
      // The case of unknown modes (coming from future versions of the service)
1105
      // is handled few lines above (search for TriggerMode_MAX).
1106
300
  }
1107
1108
300
  tracing_session->state = TracingSession::CONFIGURED;
1109
300
  PERFETTO_LOG(
1110
300
      "Configured tracing session %" PRIu64
1111
300
      ", #sources:%zu, duration:%u ms%s, #buffers:%d, total "
1112
300
      "buffer size:%zu KB, total sessions:%zu, uid:%u session name: \"%s\"",
1113
300
      tsid, cfg.data_sources().size(), tracing_session->config.duration_ms(),
1114
300
      tracing_session->config.prefer_suspend_clock_for_duration()
1115
300
          ? " (suspend_clock)"
1116
300
          : "",
1117
300
      cfg.buffers_size(), total_buf_size_kb, tracing_sessions_.size(),
1118
300
      static_cast<unsigned int>(consumer->uid_),
1119
300
      cfg.unique_session_name().c_str());
1120
1121
  // Start the data sources, unless this is a case of early setup + fast
1122
  // triggering, either through TraceConfig.deferred_start or
1123
  // TraceConfig.trigger_config(). If both are specified which ever one occurs
1124
  // first will initiate the trace.
1125
300
  if (!cfg.deferred_start() && !has_start_trigger)
1126
300
    StartTracing(tsid);
1127
1128
300
  return base::OkStatus();
1129
300
}
1130
1131
void TracingServiceImpl::ChangeTraceConfig(ConsumerEndpointImpl* consumer,
1132
0
                                           const TraceConfig& updated_cfg) {
1133
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1134
0
  TracingSession* tracing_session =
1135
0
      GetTracingSession(consumer->tracing_session_id_);
1136
0
  PERFETTO_DCHECK(tracing_session);
1137
1138
0
  if ((tracing_session->state != TracingSession::STARTED) &&
1139
0
      (tracing_session->state != TracingSession::CONFIGURED)) {
1140
0
    PERFETTO_ELOG(
1141
0
        "ChangeTraceConfig() was called for a tracing session which isn't "
1142
0
        "running.");
1143
0
    return;
1144
0
  }
1145
1146
  // We only support updating producer_name_{,regex}_filter (and pass-through
1147
  // configs) for now; null out any changeable fields and make sure the rest are
1148
  // identical.
1149
0
  TraceConfig new_config_copy(updated_cfg);
1150
0
  for (auto& ds_cfg : *new_config_copy.mutable_data_sources()) {
1151
0
    ds_cfg.clear_producer_name_filter();
1152
0
    ds_cfg.clear_producer_name_regex_filter();
1153
0
  }
1154
1155
0
  TraceConfig current_config_copy(tracing_session->config);
1156
0
  for (auto& ds_cfg : *current_config_copy.mutable_data_sources()) {
1157
0
    ds_cfg.clear_producer_name_filter();
1158
0
    ds_cfg.clear_producer_name_regex_filter();
1159
0
  }
1160
1161
0
  if (new_config_copy != current_config_copy) {
1162
0
    PERFETTO_LOG(
1163
0
        "ChangeTraceConfig() was called with a config containing unsupported "
1164
0
        "changes; only adding to the producer_name_{,regex}_filter is "
1165
0
        "currently supported and will have an effect.");
1166
0
  }
1167
1168
0
  for (TraceConfig::DataSource& cfg_data_source :
1169
0
       *tracing_session->config.mutable_data_sources()) {
1170
    // Find the updated producer_filter in the new config.
1171
0
    std::vector<std::string> new_producer_name_filter;
1172
0
    std::vector<std::string> new_producer_name_regex_filter;
1173
0
    bool found_data_source = false;
1174
0
    for (const auto& it : updated_cfg.data_sources()) {
1175
0
      if (cfg_data_source.config().name() == it.config().name()) {
1176
0
        new_producer_name_filter = it.producer_name_filter();
1177
0
        new_producer_name_regex_filter = it.producer_name_regex_filter();
1178
0
        found_data_source = true;
1179
0
        break;
1180
0
      }
1181
0
    }
1182
1183
    // Bail out if data source not present in the new config.
1184
0
    if (!found_data_source) {
1185
0
      PERFETTO_ELOG(
1186
0
          "ChangeTraceConfig() called without a current data source also "
1187
0
          "present in the new config: %s",
1188
0
          cfg_data_source.config().name().c_str());
1189
0
      continue;
1190
0
    }
1191
1192
    // TODO(oysteine): Just replacing the filter means that if
1193
    // there are any filter entries which were present in the original config,
1194
    // but removed from the config passed to ChangeTraceConfig, any matching
1195
    // producers will keep producing but newly added producers after this
1196
    // point will never start.
1197
0
    *cfg_data_source.mutable_producer_name_filter() = new_producer_name_filter;
1198
0
    *cfg_data_source.mutable_producer_name_regex_filter() =
1199
0
        new_producer_name_regex_filter;
1200
1201
    // Get the list of producers that are already set up.
1202
0
    std::unordered_set<uint16_t> set_up_producers;
1203
0
    auto& ds_instances = tracing_session->data_source_instances;
1204
0
    for (auto instance_it = ds_instances.begin();
1205
0
         instance_it != ds_instances.end(); ++instance_it) {
1206
0
      set_up_producers.insert(instance_it->first);
1207
0
    }
1208
1209
    // Scan all the registered data sources with a matching name.
1210
0
    auto range = data_sources_.equal_range(cfg_data_source.config().name());
1211
0
    for (auto it = range.first; it != range.second; it++) {
1212
0
      ProducerEndpointImpl* producer = GetProducer(it->second.producer_id);
1213
0
      PERFETTO_DCHECK(producer);
1214
1215
      // Check if the producer name of this data source is present
1216
      // in the name filters. We currently only support new filters, not
1217
      // removing old ones.
1218
0
      if (!NameMatchesFilter(producer->name_, new_producer_name_filter,
1219
0
                             new_producer_name_regex_filter)) {
1220
0
        continue;
1221
0
      }
1222
1223
      // If this producer is already set up, we assume that all datasources
1224
      // in it started already.
1225
0
      if (set_up_producers.count(it->second.producer_id))
1226
0
        continue;
1227
1228
      // If it wasn't previously setup, set it up now.
1229
      // (The per-producer config is optional).
1230
0
      TraceConfig::ProducerConfig producer_config;
1231
0
      for (const auto& config : tracing_session->config.producers()) {
1232
0
        if (producer->name_ == config.producer_name()) {
1233
0
          producer_config = config;
1234
0
          break;
1235
0
        }
1236
0
      }
1237
1238
0
      DataSourceInstance* ds_inst = SetupDataSource(
1239
0
          cfg_data_source, producer_config, it->second, tracing_session);
1240
1241
0
      if (ds_inst && tracing_session->state == TracingSession::STARTED)
1242
0
        StartDataSourceInstance(producer, tracing_session, ds_inst);
1243
0
    }
1244
0
  }
1245
0
}
1246
1247
uint32_t TracingServiceImpl::DelayToNextWritePeriodMs(
1248
0
    const TracingSession& session) {
1249
0
  PERFETTO_DCHECK(session.write_period_ms > 0);
1250
0
  return session.write_period_ms -
1251
0
         static_cast<uint32_t>(clock_->GetWallTimeMs().count() %
1252
0
                               session.write_period_ms);
1253
0
}
1254
1255
300
void TracingServiceImpl::StartTracing(TracingSessionID tsid) {
1256
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
1257
1258
300
  TracingSession* tracing_session = GetTracingSession(tsid);
1259
300
  if (!tracing_session) {
1260
0
    PERFETTO_ELOG("StartTracing() failed, invalid session ID %" PRIu64, tsid);
1261
0
    return;
1262
0
  }
1263
1264
300
  MaybeLogUploadEvent(tracing_session->config, tracing_session->trace_uuid,
1265
300
                      PerfettoStatsdAtom::kTracedStartTracing);
1266
1267
300
  if (tracing_session->state != TracingSession::CONFIGURED) {
1268
0
    MaybeLogUploadEvent(
1269
0
        tracing_session->config, tracing_session->trace_uuid,
1270
0
        PerfettoStatsdAtom::kTracedStartTracingInvalidSessionState);
1271
0
    PERFETTO_ELOG("StartTracing() failed, invalid session state: %d",
1272
0
                  tracing_session->state);
1273
0
    return;
1274
0
  }
1275
1276
300
  tracing_session->state = TracingSession::STARTED;
1277
1278
  // We store the start of trace snapshot separately as it's important to make
1279
  // sure we can interpret all the data in the trace and storing it in the ring
1280
  // buffer means it could be overwritten by a later snapshot.
1281
300
  if (!tracing_session->config.builtin_data_sources()
1282
300
           .disable_clock_snapshotting()) {
1283
300
    SnapshotClocks(&tracing_session->initial_clock_snapshot);
1284
300
  }
1285
1286
  // We don't snapshot the clocks here because we just did this above.
1287
300
  SnapshotLifecycleEvent(
1288
300
      tracing_session,
1289
300
      protos::pbzero::TracingServiceEvent::kTracingStartedFieldNumber,
1290
300
      false /* snapshot_clocks */);
1291
1292
  // Periodically snapshot clocks, stats, sync markers while the trace is
1293
  // active. The snapshots are emitted on the future ReadBuffers() calls, which
1294
  // means that:
1295
  //  (a) If we're streaming to a file (or to a consumer) while tracing, we
1296
  //      write snapshots periodically into the trace.
1297
  //  (b) If ReadBuffers() is only called after tracing ends, we emit the latest
1298
  //      snapshot into the trace. For clock snapshots, we keep track of the
1299
  //      snapshot recorded at the beginning of the session
1300
  //      (initial_clock_snapshot above), as well as the most recent sampled
1301
  //      snapshots that showed significant new drift between different clocks.
1302
  //      The latter clock snapshots are sampled periodically and at lifecycle
1303
  //      events.
1304
300
  base::PeriodicTask::Args snapshot_task_args;
1305
300
  snapshot_task_args.start_first_task_immediately = true;
1306
300
  snapshot_task_args.use_suspend_aware_timer =
1307
300
      tracing_session->config.builtin_data_sources()
1308
300
          .prefer_suspend_clock_for_snapshot();
1309
300
  snapshot_task_args.task = [this, tsid] { PeriodicSnapshotTask(tsid); };
1310
300
  snapshot_task_args.period_ms =
1311
300
      tracing_session->config.builtin_data_sources().snapshot_interval_ms();
1312
300
  if (!snapshot_task_args.period_ms)
1313
300
    snapshot_task_args.period_ms = kDefaultSnapshotsIntervalMs;
1314
300
  tracing_session->snapshot_periodic_task.Start(snapshot_task_args);
1315
1316
  // Trigger delayed task if the trace is time limited.
1317
300
  const uint32_t trace_duration_ms = tracing_session->config.duration_ms();
1318
300
  if (trace_duration_ms > 0) {
1319
0
    auto stop_task =
1320
0
        std::bind(&TracingServiceImpl::StopOnDurationMsExpiry, this, tsid);
1321
0
    if (tracing_session->config.prefer_suspend_clock_for_duration()) {
1322
0
      base::PeriodicTask::Args stop_args;
1323
0
      stop_args.use_suspend_aware_timer = true;
1324
0
      stop_args.period_ms = trace_duration_ms;
1325
0
      stop_args.one_shot = true;
1326
0
      stop_args.task = std::move(stop_task);
1327
0
      tracing_session->timed_stop_task.Start(stop_args);
1328
0
    } else {
1329
0
      weak_runner_.PostDelayedTask(std::move(stop_task), trace_duration_ms);
1330
0
    }
1331
0
  }  // if (trace_duration_ms > 0).
1332
1333
  // Start the periodic drain tasks if we should to save the trace into a file.
1334
300
  if (tracing_session->config.write_into_file()) {
1335
0
    weak_runner_.PostDelayedTask([this, tsid] { ReadBuffersIntoFile(tsid); },
1336
0
                                 DelayToNextWritePeriodMs(*tracing_session));
1337
0
  }
1338
1339
  // Start the periodic flush tasks if the config specified a flush period.
1340
300
  if (tracing_session->config.flush_period_ms())
1341
0
    PeriodicFlushTask(tsid, /*post_next_only=*/true);
1342
1343
  // Start the periodic incremental state clear tasks if the config specified a
1344
  // period.
1345
300
  if (tracing_session->config.incremental_state_config().clear_period_ms()) {
1346
0
    PeriodicClearIncrementalStateTask(tsid, /*post_next_only=*/true);
1347
0
  }
1348
1349
300
  for (auto& [prod_id, data_source] : tracing_session->data_source_instances) {
1350
87
    ProducerEndpointImpl* producer = GetProducer(prod_id);
1351
87
    if (!producer) {
1352
0
      PERFETTO_DFATAL("Producer does not exist.");
1353
0
      continue;
1354
0
    }
1355
87
    StartDataSourceInstance(producer, tracing_session, &data_source);
1356
87
  }
1357
1358
300
  MaybeNotifyAllDataSourcesStarted(tracing_session);
1359
1360
  // `did_notify_all_data_source_started` is only set if a consumer is
1361
  // connected.
1362
300
  if (tracing_session->consumer_maybe_null) {
1363
300
    weak_runner_.PostDelayedTask(
1364
300
        [this, tsid] { OnAllDataSourceStartedTimeout(tsid); },
1365
300
        kAllDataSourceStartedTimeout);
1366
300
  }
1367
300
}
1368
1369
0
void TracingServiceImpl::StopOnDurationMsExpiry(TracingSessionID tsid) {
1370
0
  auto* tracing_session_ptr = GetTracingSession(tsid);
1371
0
  if (!tracing_session_ptr)
1372
0
    return;
1373
  // If this trace was using STOP_TRACING triggers and we've seen
1374
  // one, then the trigger overrides the normal timeout. In this
1375
  // case we just return and let the other task clean up this trace.
1376
0
  if (GetTriggerMode(tracing_session_ptr->config) ==
1377
0
          TraceConfig::TriggerConfig::STOP_TRACING &&
1378
0
      !tracing_session_ptr->received_triggers.empty())
1379
0
    return;
1380
  // In all other cases (START_TRACING or no triggers) we flush
1381
  // after |trace_duration_ms| unconditionally.
1382
0
  FlushAndDisableTracing(tsid);
1383
0
}
1384
1385
void TracingServiceImpl::StartDataSourceInstance(
1386
    ProducerEndpointImpl* producer,
1387
    TracingSession* tracing_session,
1388
300
    TracingServiceImpl::DataSourceInstance* instance) {
1389
300
  PERFETTO_DCHECK(instance->state == DataSourceInstance::CONFIGURED);
1390
1391
300
  bool start_immediately = !instance->will_notify_on_start;
1392
1393
300
  if (producer->IsAndroidProcessFrozen()) {
1394
0
    PERFETTO_DLOG(
1395
0
        "skipping waiting of data source \"%s\" on producer \"%s\" (pid=%u) "
1396
0
        "because it is frozen",
1397
0
        instance->data_source_name.c_str(), producer->name_.c_str(),
1398
0
        producer->pid());
1399
0
    start_immediately = true;
1400
0
  }
1401
1402
300
  if (!start_immediately) {
1403
0
    instance->state = DataSourceInstance::STARTING;
1404
300
  } else {
1405
300
    instance->state = DataSourceInstance::STARTED;
1406
300
  }
1407
300
  if (tracing_session->consumer_maybe_null) {
1408
300
    tracing_session->consumer_maybe_null->OnDataSourceInstanceStateChange(
1409
300
        *producer, *instance);
1410
300
  }
1411
300
  producer->StartDataSource(instance->instance_id, instance->config);
1412
1413
  // If all data sources are started, notify the consumer.
1414
300
  if (instance->state == DataSourceInstance::STARTED)
1415
300
    MaybeNotifyAllDataSourcesStarted(tracing_session);
1416
300
}
1417
1418
// DisableTracing just stops the data sources but doesn't free up any buffer.
1419
// This is to allow the consumer to freeze the buffers (by stopping the trace)
1420
// and then drain the buffers. The actual teardown of the TracingSession happens
1421
// in FreeBuffers().
1422
void TracingServiceImpl::DisableTracing(TracingSessionID tsid,
1423
300
                                        bool disable_immediately) {
1424
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
1425
300
  TracingSession* tracing_session = GetTracingSession(tsid);
1426
300
  if (!tracing_session) {
1427
    // Can happen if the consumer calls this before EnableTracing() or after
1428
    // FreeBuffers().
1429
0
    PERFETTO_DLOG("DisableTracing() failed, invalid session ID %" PRIu64, tsid);
1430
0
    return;
1431
0
  }
1432
1433
300
  MaybeLogUploadEvent(tracing_session->config, tracing_session->trace_uuid,
1434
300
                      PerfettoStatsdAtom::kTracedDisableTracing);
1435
1436
300
  switch (tracing_session->state) {
1437
    // Spurious call to DisableTracing() while already disabled, nothing to do.
1438
0
    case TracingSession::DISABLED:
1439
0
      PERFETTO_DCHECK(tracing_session->AllDataSourceInstancesStopped());
1440
0
      return;
1441
1442
0
    case TracingSession::CLONED_READ_ONLY:
1443
0
      return;
1444
1445
    // This is either:
1446
    // A) The case of a graceful DisableTracing() call followed by a call to
1447
    //    FreeBuffers(), iff |disable_immediately| == true. In this case we want
1448
    //    to forcefully transition in the disabled state without waiting for the
1449
    //    outstanding acks because the buffers are going to be destroyed soon.
1450
    // B) A spurious call, iff |disable_immediately| == false, in which case
1451
    //    there is nothing to do.
1452
0
    case TracingSession::DISABLING_WAITING_STOP_ACKS:
1453
0
      PERFETTO_DCHECK(!tracing_session->AllDataSourceInstancesStopped());
1454
0
      if (disable_immediately)
1455
0
        DisableTracingNotifyConsumerAndFlushFile(tracing_session);
1456
0
      return;
1457
1458
    // Continues below.
1459
0
    case TracingSession::CONFIGURED:
1460
      // If the session didn't even start there is no need to orchestrate a
1461
      // graceful stop of data sources.
1462
0
      disable_immediately = true;
1463
0
      break;
1464
1465
    // This is the nominal case, continues below.
1466
300
    case TracingSession::STARTED:
1467
300
      break;
1468
300
  }
1469
1470
300
  for (auto& data_source_inst : tracing_session->data_source_instances) {
1471
0
    const ProducerID producer_id = data_source_inst.first;
1472
0
    DataSourceInstance& instance = data_source_inst.second;
1473
0
    ProducerEndpointImpl* producer = GetProducer(producer_id);
1474
0
    PERFETTO_DCHECK(producer);
1475
0
    PERFETTO_DCHECK(instance.state == DataSourceInstance::CONFIGURED ||
1476
0
                    instance.state == DataSourceInstance::STARTING ||
1477
0
                    instance.state == DataSourceInstance::STARTED);
1478
0
    StopDataSourceInstance(producer, tracing_session, &instance,
1479
0
                           disable_immediately);
1480
0
  }
1481
1482
  // If the periodic task is running, we can stop the periodic snapshot timer
1483
  // here instead of waiting until FreeBuffers to prevent useless snapshots
1484
  // which won't be read.
1485
300
  tracing_session->snapshot_periodic_task.Reset();
1486
1487
  // Either this request is flagged with |disable_immediately| or there are no
1488
  // data sources that are requesting a final handshake. In both cases just mark
1489
  // the session as disabled immediately, notify the consumer and flush the
1490
  // trace file (if used).
1491
300
  if (tracing_session->AllDataSourceInstancesStopped())
1492
300
    return DisableTracingNotifyConsumerAndFlushFile(tracing_session);
1493
1494
0
  tracing_session->state = TracingSession::DISABLING_WAITING_STOP_ACKS;
1495
0
  weak_runner_.PostDelayedTask([this, tsid] { OnDisableTracingTimeout(tsid); },
1496
0
                               tracing_session->data_source_stop_timeout_ms());
1497
1498
  // Deliberately NOT removing the session from |tracing_session_|, it's still
1499
  // needed to call ReadBuffers(). FreeBuffers() will erase() the session.
1500
0
}
1501
1502
void TracingServiceImpl::NotifyDataSourceStarted(
1503
    ProducerID producer_id,
1504
0
    DataSourceInstanceID instance_id) {
1505
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1506
0
  for (auto& kv : tracing_sessions_) {
1507
0
    TracingSession& tracing_session = kv.second;
1508
0
    DataSourceInstance* instance =
1509
0
        tracing_session.GetDataSourceInstance(producer_id, instance_id);
1510
1511
0
    if (!instance)
1512
0
      continue;
1513
1514
    // If the tracing session was already stopped, ignore this notification.
1515
0
    if (tracing_session.state != TracingSession::STARTED)
1516
0
      continue;
1517
1518
0
    if (instance->state != DataSourceInstance::STARTING) {
1519
0
      PERFETTO_ELOG("Started data source instance in incorrect state: %d",
1520
0
                    instance->state);
1521
0
      continue;
1522
0
    }
1523
1524
0
    instance->state = DataSourceInstance::STARTED;
1525
1526
0
    ProducerEndpointImpl* producer = GetProducer(producer_id);
1527
0
    PERFETTO_DCHECK(producer);
1528
0
    if (tracing_session.consumer_maybe_null) {
1529
0
      tracing_session.consumer_maybe_null->OnDataSourceInstanceStateChange(
1530
0
          *producer, *instance);
1531
0
    }
1532
1533
    // If all data sources are started, notify the consumer.
1534
0
    MaybeNotifyAllDataSourcesStarted(&tracing_session);
1535
0
  }  // for (tracing_session)
1536
0
}
1537
1538
0
void TracingServiceImpl::OnAllDataSourceStartedTimeout(TracingSessionID tsid) {
1539
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1540
0
  TracingSession* tracing_session = GetTracingSession(tsid);
1541
  // It would be possible to check for `AllDataSourceInstancesStarted()` here,
1542
  // but it doesn't make much sense, because a data source can be registered
1543
  // after the session has started. Therefore this is tied to
1544
  // `did_notify_all_data_source_started`: if that notification happened, do not
1545
  // record slow data sources.
1546
0
  if (!tracing_session || !tracing_session->consumer_maybe_null ||
1547
0
      tracing_session->did_notify_all_data_source_started) {
1548
0
    return;
1549
0
  }
1550
1551
0
  int64_t timestamp = clock_->GetBootTimeNs().count();
1552
1553
0
  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
1554
0
  packet->set_timestamp(static_cast<uint64_t>(timestamp));
1555
0
  packet->set_trusted_uid(static_cast<int32_t>(uid_));
1556
0
  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
1557
1558
0
  size_t i = 0;
1559
0
  protos::pbzero::TracingServiceEvent::DataSources* slow_data_sources =
1560
0
      packet->set_service_event()->set_slow_starting_data_sources();
1561
0
  for (const auto& [producer_id, ds_instance] :
1562
0
       tracing_session->data_source_instances) {
1563
0
    if (ds_instance.state == DataSourceInstance::STARTED) {
1564
0
      continue;
1565
0
    }
1566
0
    ProducerEndpointImpl* producer = GetProducer(producer_id);
1567
0
    if (!producer) {
1568
0
      continue;
1569
0
    }
1570
0
    if (++i > kMaxLifecycleEventsListedDataSources) {
1571
0
      break;
1572
0
    }
1573
0
    auto* ds = slow_data_sources->add_data_source();
1574
0
    ds->set_producer_name(producer->name_);
1575
0
    ds->set_data_source_name(ds_instance.data_source_name);
1576
0
    PERFETTO_LOG(
1577
0
        "Data source failed to start within 20s data_source=\"%s\", "
1578
0
        "producer=\"%s\", tsid=%" PRIu64,
1579
0
        ds_instance.data_source_name.c_str(), producer->name_.c_str(), tsid);
1580
0
  }
1581
1582
0
  tracing_session->slow_start_event = TracingSession::ArbitraryLifecycleEvent{
1583
0
      timestamp, packet.SerializeAsArray()};
1584
0
}
1585
1586
void TracingServiceImpl::MaybeNotifyAllDataSourcesStarted(
1587
900
    TracingSession* tracing_session) {
1588
900
  if (!tracing_session->consumer_maybe_null)
1589
0
    return;
1590
1591
900
  if (!tracing_session->AllDataSourceInstancesStarted())
1592
0
    return;
1593
1594
  // In some rare cases, we can get in this state more than once. Consider the
1595
  // following scenario: 3 data sources are registered -> trace starts ->
1596
  // all 3 data sources ack -> OnAllDataSourcesStarted() is called.
1597
  // Imagine now that a 4th data source registers while the trace is ongoing.
1598
  // This would hit the AllDataSourceInstancesStarted() condition again.
1599
  // In this case, however, we don't want to re-notify the consumer again.
1600
  // That would be unexpected (even if, perhaps, technically correct) and
1601
  // trigger bugs in the consumer.
1602
900
  if (tracing_session->did_notify_all_data_source_started)
1603
600
    return;
1604
1605
900
  PERFETTO_DLOG("All data sources started");
1606
1607
300
  SnapshotLifecycleEvent(
1608
300
      tracing_session,
1609
300
      protos::pbzero::TracingServiceEvent::kAllDataSourcesStartedFieldNumber,
1610
300
      true /* snapshot_clocks */);
1611
1612
300
  tracing_session->did_notify_all_data_source_started = true;
1613
300
  tracing_session->consumer_maybe_null->OnAllDataSourcesStarted();
1614
300
}
1615
1616
void TracingServiceImpl::NotifyDataSourceStopped(
1617
    ProducerID producer_id,
1618
0
    DataSourceInstanceID instance_id) {
1619
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1620
0
  for (auto& kv : tracing_sessions_) {
1621
0
    TracingSession& tracing_session = kv.second;
1622
0
    DataSourceInstance* instance =
1623
0
        tracing_session.GetDataSourceInstance(producer_id, instance_id);
1624
1625
0
    if (!instance)
1626
0
      continue;
1627
1628
0
    if (instance->state != DataSourceInstance::STOPPING) {
1629
0
      PERFETTO_ELOG("Stopped data source instance in incorrect state: %d",
1630
0
                    instance->state);
1631
0
      continue;
1632
0
    }
1633
1634
0
    instance->state = DataSourceInstance::STOPPED;
1635
1636
0
    ProducerEndpointImpl* producer = GetProducer(producer_id);
1637
0
    PERFETTO_DCHECK(producer);
1638
0
    if (tracing_session.consumer_maybe_null) {
1639
0
      tracing_session.consumer_maybe_null->OnDataSourceInstanceStateChange(
1640
0
          *producer, *instance);
1641
0
    }
1642
1643
0
    if (!tracing_session.AllDataSourceInstancesStopped())
1644
0
      continue;
1645
1646
0
    if (tracing_session.state != TracingSession::DISABLING_WAITING_STOP_ACKS)
1647
0
      continue;
1648
1649
    // All data sources acked the termination.
1650
0
    DisableTracingNotifyConsumerAndFlushFile(&tracing_session);
1651
0
  }  // for (tracing_session)
1652
0
}
1653
1654
void TracingServiceImpl::ActivateTriggers(
1655
    ProducerID producer_id,
1656
0
    const std::vector<std::string>& triggers) {
1657
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1658
0
  auto* producer = GetProducer(producer_id);
1659
0
  PERFETTO_DCHECK(producer);
1660
1661
0
  int64_t now_ns = clock_->GetBootTimeNs().count();
1662
0
  for (const auto& trigger_name : triggers) {
1663
0
    PERFETTO_DLOG("Received ActivateTriggers request for \"%s\"",
1664
0
                  trigger_name.c_str());
1665
0
    android_stats::MaybeLogTriggerEvent(PerfettoTriggerAtom::kTracedTrigger,
1666
0
                                        trigger_name);
1667
1668
0
    base::Hasher hash;
1669
0
    hash.Update(trigger_name.c_str(), trigger_name.size());
1670
0
    std::string triggered_session_name;
1671
0
    base::Uuid triggered_session_uuid;
1672
0
    TracingSessionID triggered_session_id = 0;
1673
0
    auto trigger_mode = TraceConfig::TriggerConfig::UNSPECIFIED;
1674
1675
0
    uint64_t trigger_name_hash = hash.digest();
1676
0
    size_t count_in_window =
1677
0
        PurgeExpiredAndCountTriggerInWindow(now_ns, trigger_name_hash);
1678
1679
0
    bool trigger_matched = false;
1680
0
    bool trigger_activated = false;
1681
0
    for (auto& id_and_tracing_session : tracing_sessions_) {
1682
0
      auto& tracing_session = id_and_tracing_session.second;
1683
0
      TracingSessionID tsid = id_and_tracing_session.first;
1684
0
      auto iter = std::find_if(
1685
0
          tracing_session.config.trigger_config().triggers().begin(),
1686
0
          tracing_session.config.trigger_config().triggers().end(),
1687
0
          [&trigger_name](const TraceConfig::TriggerConfig::Trigger& trigger) {
1688
0
            return trigger.name() == trigger_name;
1689
0
          });
1690
0
      if (iter == tracing_session.config.trigger_config().triggers().end())
1691
0
        continue;
1692
0
      if (tracing_session.state == TracingSession::CLONED_READ_ONLY)
1693
0
        continue;
1694
1695
      // If this trigger requires a certain producer to have sent it
1696
      // (non-empty producer_name()) ensure the producer who sent this trigger
1697
      // matches.
1698
0
      if (!iter->producer_name_regex().empty() &&
1699
0
          !std::regex_match(
1700
0
              producer->name_,
1701
0
              std::regex(iter->producer_name_regex(), std::regex::extended))) {
1702
0
        continue;
1703
0
      }
1704
1705
      // Use a random number between 0 and 1 to check if we should allow this
1706
      // trigger through or not.
1707
0
      double trigger_rnd = random_->GetValue();
1708
0
      PERFETTO_DCHECK(trigger_rnd >= 0 && trigger_rnd < 1);
1709
0
      if (trigger_rnd < iter->skip_probability()) {
1710
0
        MaybeLogTriggerEvent(tracing_session.config,
1711
0
                             PerfettoTriggerAtom::kTracedLimitProbability,
1712
0
                             trigger_name);
1713
0
        continue;
1714
0
      }
1715
1716
      // If we already triggered more times than the limit, silently ignore
1717
      // this trigger.
1718
0
      if (iter->max_per_24_h() > 0 && count_in_window >= iter->max_per_24_h()) {
1719
0
        MaybeLogTriggerEvent(tracing_session.config,
1720
0
                             PerfettoTriggerAtom::kTracedLimitMaxPer24h,
1721
0
                             trigger_name);
1722
0
        continue;
1723
0
      }
1724
0
      trigger_matched = true;
1725
0
      triggered_session_id = tracing_session.id;
1726
0
      triggered_session_name = tracing_session.config.unique_session_name();
1727
0
      triggered_session_uuid.set_lsb_msb(tracing_session.trace_uuid.lsb(),
1728
0
                                         tracing_session.trace_uuid.msb());
1729
0
      trigger_mode = GetTriggerMode(tracing_session.config);
1730
1731
0
      const bool triggers_already_received =
1732
0
          !tracing_session.received_triggers.empty();
1733
0
      const TriggerInfo trigger = {static_cast<uint64_t>(now_ns), iter->name(),
1734
0
                                   producer->name_, producer->uid()};
1735
0
      tracing_session.received_triggers.push_back(trigger);
1736
0
      switch (trigger_mode) {
1737
0
        case TraceConfig::TriggerConfig::START_TRACING:
1738
          // If the session has already been triggered and moved past
1739
          // CONFIGURED then we don't need to repeat StartTracing. This would
1740
          // work fine (StartTracing would return false) but would add error
1741
          // logs.
1742
0
          if (tracing_session.state != TracingSession::CONFIGURED)
1743
0
            break;
1744
1745
0
          trigger_activated = true;
1746
0
          MaybeLogUploadEvent(
1747
0
              tracing_session.config, tracing_session.trace_uuid,
1748
0
              PerfettoStatsdAtom::kTracedTriggerStartTracing, iter->name());
1749
1750
          // We override the trace duration to be the trigger's requested
1751
          // value, this ensures that the trace will end after this amount
1752
          // of time has passed.
1753
0
          tracing_session.config.set_duration_ms(iter->stop_delay_ms());
1754
0
          StartTracing(tsid);
1755
0
          break;
1756
0
        case TraceConfig::TriggerConfig::STOP_TRACING:
1757
          // Only stop the trace once to avoid confusing log messages. I.E.
1758
          // when we've already hit the first trigger we've already Posted the
1759
          // task to FlushAndDisable. So all future triggers will just break
1760
          // out.
1761
0
          if (triggers_already_received)
1762
0
            break;
1763
1764
0
          trigger_activated = true;
1765
0
          MaybeLogUploadEvent(
1766
0
              tracing_session.config, tracing_session.trace_uuid,
1767
0
              PerfettoStatsdAtom::kTracedTriggerStopTracing, iter->name());
1768
1769
          // Now that we've seen a trigger we need to stop, flush, and disable
1770
          // this session after the configured |stop_delay_ms|.
1771
0
          weak_runner_.PostDelayedTask(
1772
0
              [this, tsid] {
1773
                // Skip entirely the flush if the trace session doesn't exist
1774
                // anymore. This is to prevent misleading error messages to be
1775
                // logged.
1776
0
                if (GetTracingSession(tsid))
1777
0
                  FlushAndDisableTracing(tsid);
1778
0
              },
1779
              // If this trigger is zero this will immediately executable and
1780
              // will happen shortly.
1781
0
              iter->stop_delay_ms());
1782
0
          break;
1783
1784
0
        case TraceConfig::TriggerConfig::CLONE_SNAPSHOT:
1785
0
          trigger_activated = true;
1786
0
          MaybeLogUploadEvent(
1787
0
              tracing_session.config, tracing_session.trace_uuid,
1788
0
              PerfettoStatsdAtom::kTracedTriggerCloneSnapshot, iter->name());
1789
0
          weak_runner_.PostDelayedTask(
1790
0
              [this, tsid, trigger] {
1791
0
                auto* tsess = GetTracingSession(tsid);
1792
0
                if (!tsess || !tsess->consumer_maybe_null)
1793
0
                  return;
1794
0
                tsess->consumer_maybe_null->NotifyCloneSnapshotTrigger(trigger);
1795
0
              },
1796
0
              iter->stop_delay_ms());
1797
0
          break;
1798
1799
0
        case TraceConfig::TriggerConfig::UNSPECIFIED:
1800
0
          PERFETTO_ELOG("Trigger activated but trigger mode unspecified.");
1801
0
          break;
1802
0
      }
1803
0
    }  // for (.. : tracing_sessions_)
1804
1805
0
    if (trigger_matched) {
1806
0
      trigger_history_.emplace_back(TriggerHistory{now_ns, trigger_name_hash});
1807
0
    }
1808
1809
0
    if (trigger_activated) {
1810
      // Log only the trigger that actually caused a trace stop/start, don't log
1811
      // the follow-up ones, even if they matched.
1812
0
      PERFETTO_LOG(
1813
0
          "Trace trigger activated: trigger_name=\"%s\" trigger_mode=%d "
1814
0
          "trace_name=\"%s\" trace_uuid=\"%s\" tsid=%" PRIu64,
1815
0
          trigger_name.c_str(), trigger_mode, triggered_session_name.c_str(),
1816
0
          triggered_session_uuid.ToPrettyString().c_str(),
1817
0
          triggered_session_id);
1818
0
    }
1819
0
  }  // for (trigger_name : triggers)
1820
0
}
1821
1822
// Always invoked TraceConfig.data_source_stop_timeout_ms (by default
1823
// kDataSourceStopTimeoutMs) after DisableTracing(). In nominal conditions all
1824
// data sources should have acked the stop and this will early out.
1825
0
void TracingServiceImpl::OnDisableTracingTimeout(TracingSessionID tsid) {
1826
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1827
0
  TracingSession* tracing_session = GetTracingSession(tsid);
1828
0
  if (!tracing_session ||
1829
0
      tracing_session->state != TracingSession::DISABLING_WAITING_STOP_ACKS) {
1830
0
    return;  // Tracing session was successfully disabled.
1831
0
  }
1832
1833
0
  PERFETTO_ILOG("Timeout while waiting for ACKs for tracing session %" PRIu64,
1834
0
                tsid);
1835
0
  PERFETTO_DCHECK(!tracing_session->AllDataSourceInstancesStopped());
1836
0
  DisableTracingNotifyConsumerAndFlushFile(tracing_session);
1837
0
}
1838
1839
void TracingServiceImpl::DisableTracingNotifyConsumerAndFlushFile(
1840
300
    TracingSession* tracing_session) {
1841
300
  PERFETTO_DCHECK(tracing_session->state != TracingSession::DISABLED);
1842
300
  for (auto& inst_kv : tracing_session->data_source_instances) {
1843
0
    if (inst_kv.second.state == DataSourceInstance::STOPPED)
1844
0
      continue;
1845
0
    inst_kv.second.state = DataSourceInstance::STOPPED;
1846
0
    ProducerEndpointImpl* producer = GetProducer(inst_kv.first);
1847
0
    PERFETTO_DCHECK(producer);
1848
0
    if (tracing_session->consumer_maybe_null) {
1849
0
      tracing_session->consumer_maybe_null->OnDataSourceInstanceStateChange(
1850
0
          *producer, inst_kv.second);
1851
0
    }
1852
0
  }
1853
300
  tracing_session->state = TracingSession::DISABLED;
1854
1855
  // Scrape any remaining chunks that weren't flushed by the producers.
1856
300
  for (auto& producer_id_and_producer : producers_)
1857
0
    ScrapeSharedMemoryBuffers(tracing_session, producer_id_and_producer.second);
1858
1859
300
  SnapshotLifecycleEvent(
1860
300
      tracing_session,
1861
300
      protos::pbzero::TracingServiceEvent::kTracingDisabledFieldNumber,
1862
300
      true /* snapshot_clocks */);
1863
1864
300
  if (tracing_session->write_into_file) {
1865
0
    tracing_session->write_period_ms = 0;
1866
0
    ReadBuffersIntoFile(tracing_session->id);
1867
0
  }
1868
1869
300
  MaybeLogUploadEvent(tracing_session->config, tracing_session->trace_uuid,
1870
300
                      PerfettoStatsdAtom::kTracedNotifyTracingDisabled);
1871
1872
300
  if (tracing_session->consumer_maybe_null)
1873
300
    tracing_session->consumer_maybe_null->NotifyOnTracingDisabled("");
1874
300
}
1875
1876
void TracingServiceImpl::Flush(TracingSessionID tsid,
1877
                               uint32_t timeout_ms,
1878
                               ConsumerEndpoint::FlushCallback callback,
1879
0
                               FlushFlags flush_flags) {
1880
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1881
0
  TracingSession* tracing_session = GetTracingSession(tsid);
1882
0
  if (!tracing_session) {
1883
0
    PERFETTO_DLOG("Flush() failed, invalid session ID %" PRIu64, tsid);
1884
0
    return;
1885
0
  }
1886
1887
0
  SnapshotLifecycleEvent(
1888
0
      tracing_session,
1889
0
      protos::pbzero::TracingServiceEvent::kFlushStartedFieldNumber,
1890
0
      false /* snapshot_clocks */);
1891
1892
0
  std::map<ProducerID, std::vector<DataSourceInstanceID>> data_source_instances;
1893
0
  for (const auto& [producer_id, ds_inst] :
1894
0
       tracing_session->data_source_instances) {
1895
0
    if (ds_inst.no_flush)
1896
0
      continue;
1897
0
    data_source_instances[producer_id].push_back(ds_inst.instance_id);
1898
0
  }
1899
0
  FlushDataSourceInstances(tracing_session, timeout_ms, data_source_instances,
1900
0
                           std::move(callback), flush_flags);
1901
0
}
1902
1903
void TracingServiceImpl::FlushDataSourceInstances(
1904
    TracingSession* tracing_session,
1905
    uint32_t timeout_ms,
1906
    const std::map<ProducerID, std::vector<DataSourceInstanceID>>&
1907
        data_source_instances,
1908
    ConsumerEndpoint::FlushCallback callback,
1909
0
    FlushFlags flush_flags) {
1910
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
1911
0
  if (!timeout_ms)
1912
0
    timeout_ms = tracing_session->flush_timeout_ms();
1913
1914
0
  if (tracing_session->pending_flushes.size() > 1000) {
1915
0
    PERFETTO_ELOG("Too many flushes (%zu) pending for the tracing session",
1916
0
                  tracing_session->pending_flushes.size());
1917
0
    callback(false);
1918
0
    return;
1919
0
  }
1920
1921
0
  if (tracing_session->state != TracingSession::STARTED) {
1922
0
    PERFETTO_LOG("Flush() called, but tracing has not been started");
1923
0
    callback(false);
1924
0
    return;
1925
0
  }
1926
1927
0
  tracing_session->last_flush_events.clear();
1928
1929
0
  ++tracing_session->flushes_requested;
1930
0
  FlushRequestID flush_request_id = ++last_flush_request_id_;
1931
0
  PendingFlush& pending_flush =
1932
0
      tracing_session->pending_flushes
1933
0
          .emplace_hint(tracing_session->pending_flushes.end(),
1934
0
                        flush_request_id, PendingFlush(std::move(callback)))
1935
0
          ->second;
1936
1937
  // Send a flush request to each producer involved in the tracing session. In
1938
  // order to issue a flush request we have to build a map of all data source
1939
  // instance ids enabled for each producer.
1940
1941
0
  for (const auto& [producer_id, data_sources] : data_source_instances) {
1942
0
    ProducerEndpointImpl* producer = GetProducer(producer_id);
1943
0
    producer->Flush(flush_request_id, data_sources, flush_flags);
1944
0
    if (!producer->IsAndroidProcessFrozen()) {
1945
0
      pending_flush.producers.insert(producer_id);
1946
0
    } else {
1947
0
      PERFETTO_DLOG(
1948
0
          "skipping waiting flush for on producer \"%s\" (pid=%" PRIu32
1949
0
          ") because it is frozen",
1950
0
          producer->name_.c_str(), static_cast<uint32_t>(producer->pid()));
1951
0
    }
1952
0
  }
1953
1954
  // If there are no producers to flush (realistically this happens only in
1955
  // some tests) fire OnFlushTimeout() straight away, without waiting.
1956
0
  if (data_source_instances.empty())
1957
0
    timeout_ms = 0;
1958
1959
0
  weak_runner_.PostDelayedTask(
1960
0
      [this, tsid = tracing_session->id, flush_request_id, flush_flags] {
1961
0
        OnFlushTimeout(tsid, flush_request_id, flush_flags);
1962
0
      },
1963
0
      timeout_ms);
1964
0
}
1965
1966
void TracingServiceImpl::NotifyFlushDoneForProducer(
1967
    ProducerID producer_id,
1968
0
    FlushRequestID flush_request_id) {
1969
0
  for (auto& kv : tracing_sessions_) {
1970
    // Remove all pending flushes <= |flush_request_id| for |producer_id|.
1971
0
    auto& pending_flushes = kv.second.pending_flushes;
1972
0
    auto end_it = pending_flushes.upper_bound(flush_request_id);
1973
0
    for (auto it = pending_flushes.begin(); it != end_it;) {
1974
0
      PendingFlush& pending_flush = it->second;
1975
0
      pending_flush.producers.erase(producer_id);
1976
0
      if (pending_flush.producers.empty()) {
1977
0
        TracingSessionID tsid = kv.first;
1978
0
        auto callback = std::move(pending_flush.callback);
1979
0
        weak_runner_.PostTask([this, tsid, callback = std::move(callback)]() {
1980
0
          CompleteFlush(tsid, std::move(callback),
1981
0
                        /*success=*/true);
1982
0
        });
1983
0
        it = pending_flushes.erase(it);
1984
0
      } else {
1985
0
        it++;
1986
0
      }
1987
0
    }  // for (pending_flushes)
1988
0
  }    // for (tracing_session)
1989
0
}
1990
1991
void TracingServiceImpl::OnFlushTimeout(TracingSessionID tsid,
1992
                                        FlushRequestID flush_request_id,
1993
0
                                        FlushFlags flush_flags) {
1994
0
  TracingSession* tracing_session = GetTracingSession(tsid);
1995
0
  if (!tracing_session)
1996
0
    return;
1997
0
  auto it = tracing_session->pending_flushes.find(flush_request_id);
1998
0
  if (it == tracing_session->pending_flushes.end())
1999
0
    return;  // Nominal case: flush was completed and acked on time.
2000
2001
0
  PendingFlush& pending_flush = it->second;
2002
2003
  // If there were no producers to flush, consider it a success.
2004
0
  bool success = pending_flush.producers.empty();
2005
0
  auto callback = std::move(pending_flush.callback);
2006
  // If flush failed and this is a "final" flush, log which data sources were
2007
  // slow.
2008
0
  if ((flush_flags.reason() == FlushFlags::Reason::kTraceClone ||
2009
0
       flush_flags.reason() == FlushFlags::Reason::kTraceStop) &&
2010
0
      !success) {
2011
0
    int64_t timestamp = clock_->GetBootTimeNs().count();
2012
2013
0
    protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
2014
0
    packet->set_timestamp(static_cast<uint64_t>(timestamp));
2015
0
    packet->set_trusted_uid(static_cast<int32_t>(uid_));
2016
0
    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
2017
2018
0
    size_t i = 0;
2019
0
    protos::pbzero::TracingServiceEvent::DataSources* event =
2020
0
        packet->set_service_event()->set_last_flush_slow_data_sources();
2021
0
    for (const auto& producer_id : pending_flush.producers) {
2022
0
      ProducerEndpointImpl* producer = GetProducer(producer_id);
2023
0
      if (!producer) {
2024
0
        continue;
2025
0
      }
2026
0
      if (++i > kMaxLifecycleEventsListedDataSources) {
2027
0
        break;
2028
0
      }
2029
2030
0
      auto ds_id_range =
2031
0
          tracing_session->data_source_instances.equal_range(producer_id);
2032
0
      for (auto ds_it = ds_id_range.first; ds_it != ds_id_range.second;
2033
0
           ds_it++) {
2034
0
        auto* ds = event->add_data_source();
2035
0
        ds->set_producer_name(producer->name_);
2036
0
        ds->set_data_source_name(ds_it->second.data_source_name);
2037
0
        if (++i > kMaxLifecycleEventsListedDataSources) {
2038
0
          break;
2039
0
        }
2040
0
      }
2041
0
    }
2042
2043
0
    tracing_session->last_flush_events.push_back(
2044
0
        {timestamp, packet.SerializeAsArray()});
2045
0
  }
2046
0
  tracing_session->pending_flushes.erase(it);
2047
0
  CompleteFlush(tsid, std::move(callback), success);
2048
0
}
2049
2050
void TracingServiceImpl::CompleteFlush(TracingSessionID tsid,
2051
                                       ConsumerEndpoint::FlushCallback callback,
2052
0
                                       bool success) {
2053
0
  TracingSession* tracing_session = GetTracingSession(tsid);
2054
0
  if (!tracing_session) {
2055
0
    callback(false);
2056
0
    return;
2057
0
  }
2058
  // Producers may not have been able to flush all their data, even if they
2059
  // indicated flush completion. If possible, also collect uncommitted chunks
2060
  // to make sure we have everything they wrote so far.
2061
0
  for (auto& producer_id_and_producer : producers_) {
2062
0
    ScrapeSharedMemoryBuffers(tracing_session, producer_id_and_producer.second);
2063
0
  }
2064
0
  SnapshotLifecycleEvent(
2065
0
      tracing_session,
2066
0
      protos::pbzero::TracingServiceEvent::kAllDataSourcesFlushedFieldNumber,
2067
0
      true /* snapshot_clocks */);
2068
2069
0
  tracing_session->flushes_succeeded += success ? 1 : 0;
2070
0
  tracing_session->flushes_failed += success ? 0 : 1;
2071
0
  callback(success);
2072
0
}
2073
2074
void TracingServiceImpl::ScrapeSharedMemoryBuffers(
2075
    TracingSession* tracing_session,
2076
300
    ProducerEndpointImpl* producer) {
2077
300
  if (!producer->smb_scraping_enabled_)
2078
300
    return;
2079
2080
  // Can't copy chunks if we don't know about any trace writers.
2081
0
  if (producer->writers_.empty())
2082
0
    return;
2083
2084
  // Performance optimization: On flush or session disconnect, this method is
2085
  // called for each producer. If the producer doesn't participate in the
2086
  // session, there's no need to scape its chunks right now. We can tell if a
2087
  // producer participates in the session by checking if the producer is allowed
2088
  // to write into the session's log buffers.
2089
0
  const auto& session_buffers = tracing_session->buffers_index;
2090
0
  bool producer_in_session =
2091
0
      std::any_of(session_buffers.begin(), session_buffers.end(),
2092
0
                  [producer](BufferID buffer_id) {
2093
0
                    return producer->allowed_target_buffers_.count(buffer_id);
2094
0
                  });
2095
0
  if (!producer_in_session)
2096
0
    return;
2097
2098
0
  PERFETTO_DLOG("Scraping SMB for producer %" PRIu16, producer->id_);
2099
2100
  // Find and copy any uncommitted chunks from the SMB.
2101
  //
2102
  // In nominal conditions, the page header bitmap of the used SMB pages should
2103
  // never change because the service is the only one who is supposed to modify
2104
  // used pages (to make them free again).
2105
  //
2106
  // However, the code here needs to deal with the case of a malicious producer
2107
  // altering the SMB in unpredictable ways. Thankfully the SMB size is
2108
  // immutable, so a chunk will always point to some valid memory, even if the
2109
  // producer alters the intended layout and chunk header concurrently.
2110
  // Ultimately a malicious producer altering the SMB's chunk header bitamp
2111
  // while we are iterating in this function is not any different from the case
2112
  // of a malicious producer asking to commit a chunk made of random data,
2113
  // which is something this class has to deal with regardless.
2114
  //
2115
  // The only legitimate mutations that can happen from sane producers,
2116
  // concurrently to this function, are:
2117
  //   A. free pages being partitioned,
2118
  //   B. free chunks being migrated to kChunkBeingWritten,
2119
  //   C. kChunkBeingWritten chunks being migrated to kChunkCompleted.
2120
2121
0
  SharedMemoryABI* abi = &producer->shmem_abi_;
2122
  // num_pages() is immutable after the SMB is initialized and cannot be changed
2123
  // even by a producer even if malicious.
2124
0
  for (size_t page_idx = 0; page_idx < abi->num_pages(); page_idx++) {
2125
0
    uint32_t header_bitmap = abi->GetPageHeaderBitmap(page_idx);
2126
2127
0
    uint32_t used_chunks =
2128
0
        abi->GetUsedChunks(header_bitmap);  // Returns a bitmap.
2129
    // Skip empty pages.
2130
0
    if (used_chunks == 0)
2131
0
      continue;
2132
2133
    // Scrape the chunks that are currently used. These should be either in
2134
    // state kChunkBeingWritten or kChunkComplete.
2135
0
    for (uint32_t chunk_idx = 0; used_chunks; chunk_idx++, used_chunks >>= 1) {
2136
0
      if (!(used_chunks & 1))
2137
0
        continue;
2138
2139
0
      SharedMemoryABI::ChunkState state =
2140
0
          SharedMemoryABI::GetChunkStateFromHeaderBitmap(header_bitmap,
2141
0
                                                         chunk_idx);
2142
0
      PERFETTO_DCHECK(state == SharedMemoryABI::kChunkBeingWritten ||
2143
0
                      state == SharedMemoryABI::kChunkComplete);
2144
0
      bool chunk_complete = state == SharedMemoryABI::kChunkComplete;
2145
2146
0
      SharedMemoryABI::Chunk chunk =
2147
0
          abi->GetChunkUnchecked(page_idx, header_bitmap, chunk_idx);
2148
2149
0
      uint16_t packet_count;
2150
0
      uint8_t flags;
2151
      // GetPacketCountAndFlags has acquire_load semantics.
2152
0
      std::tie(packet_count, flags) = chunk.GetPacketCountAndFlags();
2153
2154
      // It only makes sense to copy an incomplete chunk if there's at least
2155
      // one full packet available. (The producer may not have completed the
2156
      // last packet in it yet, so we need at least 2.)
2157
0
      if (!chunk_complete && packet_count < 2)
2158
0
        continue;
2159
2160
      // At this point, it is safe to access the remaining header fields of
2161
      // the chunk. Even if the chunk was only just transferred from
2162
      // kChunkFree into kChunkBeingWritten state, the header should be
2163
      // written completely once the packet count increased above 1 (it was
2164
      // reset to 0 by the service when the chunk was freed).
2165
2166
0
      WriterID writer_id = chunk.writer_id();
2167
0
      std::optional<BufferID> target_buffer_id =
2168
0
          producer->buffer_id_for_writer(writer_id);
2169
2170
      // We can only scrape this chunk if we know which log buffer to copy it
2171
      // into.
2172
0
      if (!target_buffer_id)
2173
0
        continue;
2174
2175
      // Skip chunks that don't belong to the requested tracing session.
2176
0
      bool target_buffer_belongs_to_session =
2177
0
          std::find(session_buffers.begin(), session_buffers.end(),
2178
0
                    *target_buffer_id) != session_buffers.end();
2179
0
      if (!target_buffer_belongs_to_session)
2180
0
        continue;
2181
2182
0
      uint32_t chunk_id =
2183
0
          chunk.header()->chunk_id.load(std::memory_order_relaxed);
2184
2185
0
      CopyProducerPageIntoLogBuffer(
2186
0
          producer->id_, producer->client_identity_, writer_id, chunk_id,
2187
0
          *target_buffer_id, packet_count, flags, chunk_complete,
2188
0
          chunk.payload_begin(), chunk.payload_size());
2189
0
    }
2190
0
  }
2191
0
}
2192
2193
0
void TracingServiceImpl::FlushAndDisableTracing(TracingSessionID tsid) {
2194
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
2195
0
  PERFETTO_DLOG("Triggering final flush for %" PRIu64, tsid);
2196
0
  Flush(
2197
0
      tsid, 0,
2198
0
      [this, tsid](bool success) {
2199
        // This was a DLOG up to Jun 2021 (v16, Android S).
2200
0
        PERFETTO_LOG("FlushAndDisableTracing(%" PRIu64 ") done, success=%d",
2201
0
                     tsid, success);
2202
0
        TracingSession* session = GetTracingSession(tsid);
2203
0
        if (!session) {
2204
0
          return;
2205
0
        }
2206
0
        session->final_flush_outcome = success
2207
0
                                           ? TraceStats::FINAL_FLUSH_SUCCEEDED
2208
0
                                           : TraceStats::FINAL_FLUSH_FAILED;
2209
0
        if (session->consumer_maybe_null) {
2210
          // If the consumer is still attached, just disable the session but
2211
          // give it a chance to read the contents.
2212
0
          DisableTracing(tsid);
2213
0
        } else {
2214
          // If the consumer detached, destroy the session. If the consumer did
2215
          // start the session in long-tracing mode, the service will have saved
2216
          // the contents to the passed file. If not, the contents will be
2217
          // destroyed.
2218
0
          FreeBuffers(tsid);
2219
0
        }
2220
0
      },
2221
0
      FlushFlags(FlushFlags::Initiator::kTraced,
2222
0
                 FlushFlags::Reason::kTraceStop));
2223
0
}
2224
2225
void TracingServiceImpl::PeriodicFlushTask(TracingSessionID tsid,
2226
0
                                           bool post_next_only) {
2227
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
2228
0
  TracingSession* tracing_session = GetTracingSession(tsid);
2229
0
  if (!tracing_session || tracing_session->state != TracingSession::STARTED)
2230
0
    return;
2231
2232
0
  uint32_t flush_period_ms = tracing_session->config.flush_period_ms();
2233
0
  weak_runner_.PostDelayedTask(
2234
0
      [this, tsid] { PeriodicFlushTask(tsid, /*post_next_only=*/false); },
2235
0
      flush_period_ms - static_cast<uint32_t>(clock_->GetWallTimeMs().count() %
2236
0
                                              flush_period_ms));
2237
2238
0
  if (post_next_only)
2239
0
    return;
2240
2241
0
  PERFETTO_DLOG("Triggering periodic flush for trace session %" PRIu64, tsid);
2242
0
  Flush(
2243
0
      tsid, 0,
2244
0
      [](bool success) {
2245
0
        if (!success)
2246
0
          PERFETTO_ELOG("Periodic flush timed out");
2247
0
      },
2248
0
      FlushFlags(FlushFlags::Initiator::kTraced,
2249
0
                 FlushFlags::Reason::kPeriodic));
2250
0
}
2251
2252
void TracingServiceImpl::PeriodicClearIncrementalStateTask(
2253
    TracingSessionID tsid,
2254
0
    bool post_next_only) {
2255
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
2256
0
  TracingSession* tracing_session = GetTracingSession(tsid);
2257
0
  if (!tracing_session || tracing_session->state != TracingSession::STARTED)
2258
0
    return;
2259
2260
0
  uint32_t clear_period_ms =
2261
0
      tracing_session->config.incremental_state_config().clear_period_ms();
2262
0
  weak_runner_.PostDelayedTask(
2263
0
      [this, tsid] {
2264
0
        PeriodicClearIncrementalStateTask(tsid, /*post_next_only=*/false);
2265
0
      },
2266
0
      clear_period_ms - static_cast<uint32_t>(clock_->GetWallTimeMs().count() %
2267
0
                                              clear_period_ms));
2268
2269
0
  if (post_next_only)
2270
0
    return;
2271
2272
0
  PERFETTO_DLOG(
2273
0
      "Performing periodic incremental state clear for trace session %" PRIu64,
2274
0
      tsid);
2275
2276
  // Queue the IPCs to producers with active data sources that opted in.
2277
0
  std::map<ProducerID, std::vector<DataSourceInstanceID>> clear_map;
2278
0
  for (const auto& kv : tracing_session->data_source_instances) {
2279
0
    ProducerID producer_id = kv.first;
2280
0
    const DataSourceInstance& data_source = kv.second;
2281
0
    if (data_source.handles_incremental_state_clear) {
2282
0
      clear_map[producer_id].push_back(data_source.instance_id);
2283
0
    }
2284
0
  }
2285
2286
0
  for (const auto& kv : clear_map) {
2287
0
    ProducerID producer_id = kv.first;
2288
0
    const std::vector<DataSourceInstanceID>& data_sources = kv.second;
2289
0
    ProducerEndpointImpl* producer = GetProducer(producer_id);
2290
0
    if (!producer) {
2291
0
      PERFETTO_DFATAL("Producer does not exist.");
2292
0
      continue;
2293
0
    }
2294
0
    producer->ClearIncrementalState(data_sources);
2295
0
  }
2296
0
}
2297
2298
bool TracingServiceImpl::ReadBuffersIntoConsumer(
2299
    TracingSessionID tsid,
2300
300
    ConsumerEndpointImpl* consumer) {
2301
300
  PERFETTO_DCHECK(consumer);
2302
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
2303
300
  TracingSession* tracing_session = GetTracingSession(tsid);
2304
300
  if (!tracing_session) {
2305
0
    PERFETTO_DLOG(
2306
0
        "Cannot ReadBuffersIntoConsumer(): no tracing session is active");
2307
0
    return false;
2308
0
  }
2309
2310
300
  if (tracing_session->write_into_file) {
2311
    // If the consumer enabled tracing and asked to save the contents into the
2312
    // passed file makes little sense to also try to read the buffers over IPC,
2313
    // as that would just steal data from the periodic draining task.
2314
0
    PERFETTO_ELOG("Consumer trying to read from write_into_file session.");
2315
0
    return false;
2316
0
  }
2317
2318
300
  if (IsWaitingForTrigger(tracing_session))
2319
0
    return false;
2320
2321
  // This is a rough threshold to determine how much to read from the buffer in
2322
  // each task. This is to avoid executing a single huge sending task for too
2323
  // long and risk to hit the watchdog. This is *not* an upper bound: we just
2324
  // stop accumulating new packets and PostTask *after* we cross this threshold.
2325
  // This constant essentially balances the PostTask and IPC overhead vs the
2326
  // responsiveness of the service. An extremely small value will cause one IPC
2327
  // and one PostTask for each slice but will keep the service extremely
2328
  // responsive. An extremely large value will batch the send for the full
2329
  // buffer in one large task, will hit the blocking send() once the socket
2330
  // buffers are full and hang the service for a bit (until the consumer
2331
  // catches up).
2332
300
  static constexpr size_t kApproxBytesPerTask = 32768;
2333
300
  bool has_more;
2334
300
  std::vector<TracePacket> packets =
2335
300
      ReadBuffers(tracing_session, kApproxBytesPerTask, &has_more);
2336
2337
300
  if (has_more) {
2338
0
    auto weak_consumer = consumer->weak_ptr_factory_.GetWeakPtr();
2339
0
    weak_runner_.PostTask(
2340
0
        [this, weak_consumer = std::move(weak_consumer), tsid] {
2341
0
          if (!weak_consumer)
2342
0
            return;
2343
0
          ReadBuffersIntoConsumer(tsid, weak_consumer.get());
2344
0
        });
2345
0
  }
2346
2347
  // Keep this as tail call, just in case the consumer re-enters.
2348
300
  consumer->consumer_->OnTraceData(std::move(packets), has_more);
2349
300
  return true;
2350
300
}
2351
2352
0
bool TracingServiceImpl::ReadBuffersIntoFile(TracingSessionID tsid) {
2353
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
2354
0
  TracingSession* tracing_session = GetTracingSession(tsid);
2355
0
  if (!tracing_session) {
2356
    // This will be hit systematically from the PostDelayedTask. Avoid logging,
2357
    // it would be just spam.
2358
0
    return false;
2359
0
  }
2360
2361
  // This can happen if the file is closed by a previous task because it reaches
2362
  // |max_file_size_bytes|.
2363
0
  if (!tracing_session->write_into_file)
2364
0
    return false;
2365
2366
0
  if (IsWaitingForTrigger(tracing_session))
2367
0
    return false;
2368
2369
  // ReadBuffers() can allocate memory internally, for filtering. By limiting
2370
  // the data that ReadBuffers() reads to kWriteIntoChunksSize per iteration,
2371
  // we limit the amount of memory used on each iteration.
2372
  //
2373
  // It would be tempting to split this into multiple tasks like in
2374
  // ReadBuffersIntoConsumer, but that's not currently possible.
2375
  // ReadBuffersIntoFile has to read the whole available data before returning,
2376
  // to support the disable_immediately=true code paths.
2377
0
  bool has_more = true;
2378
0
  bool stop_writing_into_file = false;
2379
0
  do {
2380
0
    std::vector<TracePacket> packets =
2381
0
        ReadBuffers(tracing_session, kWriteIntoFileChunkSize, &has_more);
2382
2383
0
    stop_writing_into_file = WriteIntoFile(tracing_session, std::move(packets));
2384
0
  } while (has_more && !stop_writing_into_file);
2385
2386
0
  if (stop_writing_into_file || tracing_session->write_period_ms == 0) {
2387
    // Ensure all data was written to the file before we close it.
2388
0
    base::FlushFile(tracing_session->write_into_file.get());
2389
0
    tracing_session->write_into_file.reset();
2390
0
    tracing_session->write_period_ms = 0;
2391
0
    if (tracing_session->state == TracingSession::STARTED)
2392
0
      DisableTracing(tsid);
2393
0
    return true;
2394
0
  }
2395
2396
0
  weak_runner_.PostDelayedTask([this, tsid] { ReadBuffersIntoFile(tsid); },
2397
0
                               DelayToNextWritePeriodMs(*tracing_session));
2398
0
  return true;
2399
0
}
2400
2401
300
bool TracingServiceImpl::IsWaitingForTrigger(TracingSession* tracing_session) {
2402
  // Ignore the logic below for cloned tracing sessions. In this case we
2403
  // actually want to read the (cloned) trace buffers even if no trigger was
2404
  // hit.
2405
300
  if (tracing_session->state == TracingSession::CLONED_READ_ONLY) {
2406
0
    return false;
2407
0
  }
2408
2409
  // When a tracing session is waiting for a trigger, it is considered empty. If
2410
  // a tracing session finishes and moves into DISABLED without ever receiving a
2411
  // trigger, the trace should never return any data. This includes the
2412
  // synthetic packets like TraceConfig and Clock snapshots. So we bail out
2413
  // early and let the consumer know there is no data.
2414
300
  if (!tracing_session->config.trigger_config().triggers().empty() &&
2415
0
      tracing_session->received_triggers.empty()) {
2416
0
    PERFETTO_DLOG(
2417
0
        "ReadBuffers(): tracing session has not received a trigger yet.");
2418
0
    return true;
2419
0
  }
2420
2421
  // Traces with CLONE_SNAPSHOT triggers are a special case of the above. They
2422
  // can be read only via a CloneSession() request. This is to keep the
2423
  // behavior consistent with the STOP_TRACING+triggers case and avoid periodic
2424
  // finalizations and uploads of the main CLONE_SNAPSHOT triggers.
2425
300
  if (GetTriggerMode(tracing_session->config) ==
2426
300
      TraceConfig::TriggerConfig::CLONE_SNAPSHOT) {
2427
0
    PERFETTO_DLOG(
2428
0
        "ReadBuffers(): skipping because the tracing session has "
2429
0
        "CLONE_SNAPSHOT triggers defined");
2430
0
    return true;
2431
0
  }
2432
2433
300
  return false;
2434
300
}
2435
2436
std::vector<TracePacket> TracingServiceImpl::ReadBuffers(
2437
    TracingSession* tracing_session,
2438
    size_t threshold,
2439
300
    bool* has_more) {
2440
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
2441
300
  PERFETTO_DCHECK(tracing_session);
2442
300
  *has_more = false;
2443
2444
300
  std::vector<TracePacket> packets;
2445
300
  packets.reserve(1024);  // Just an educated guess to avoid trivial expansions.
2446
2447
300
  if (!tracing_session->initial_clock_snapshot.empty()) {
2448
300
    EmitClockSnapshot(tracing_session,
2449
300
                      std::move(tracing_session->initial_clock_snapshot),
2450
300
                      &packets);
2451
300
  }
2452
2453
300
  for (auto& snapshot : tracing_session->clock_snapshot_ring_buffer) {
2454
300
    PERFETTO_DCHECK(!snapshot.empty());
2455
300
    EmitClockSnapshot(tracing_session, std::move(snapshot), &packets);
2456
300
  }
2457
300
  tracing_session->clock_snapshot_ring_buffer.clear();
2458
2459
300
  if (tracing_session->should_emit_sync_marker) {
2460
300
    EmitSyncMarker(&packets);
2461
300
    tracing_session->should_emit_sync_marker = false;
2462
300
  }
2463
2464
300
  if (!tracing_session->config.builtin_data_sources().disable_trace_config()) {
2465
300
    MaybeEmitTraceConfig(tracing_session, &packets);
2466
300
    MaybeEmitCloneTrigger(tracing_session, &packets);
2467
300
    MaybeEmitReceivedTriggers(tracing_session, &packets);
2468
300
  }
2469
300
  if (!tracing_session->did_emit_initial_packets) {
2470
300
    EmitUuid(tracing_session, &packets);
2471
300
    if (!tracing_session->config.builtin_data_sources().disable_system_info())
2472
300
      EmitSystemInfo(&packets);
2473
300
  }
2474
300
  tracing_session->did_emit_initial_packets = true;
2475
2476
  // Note that in the proto comment, we guarantee that the tracing_started
2477
  // lifecycle event will be emitted before any data packets so make sure to
2478
  // keep this before reading the tracing buffers.
2479
300
  if (!tracing_session->config.builtin_data_sources().disable_service_events())
2480
300
    EmitLifecycleEvents(tracing_session, &packets);
2481
2482
  // In a multi-machine tracing session, emit clock synchronization messages for
2483
  // remote machines.
2484
300
  if (!relay_clients_.empty())
2485
0
    MaybeEmitRemoteClockSync(tracing_session, &packets);
2486
2487
300
  size_t packets_bytes = 0;  // SUM(slice.size() for each slice in |packets|).
2488
2489
  // Add up size for packets added by the Maybe* calls above.
2490
2.40k
  for (const TracePacket& packet : packets) {
2491
2.40k
    packets_bytes += packet.size();
2492
2.40k
  }
2493
2494
300
  bool did_hit_threshold = false;
2495
2496
300
  for (size_t buf_idx = 0;
2497
600
       buf_idx < tracing_session->num_buffers() && !did_hit_threshold;
2498
300
       buf_idx++) {
2499
300
    auto tbuf_iter = buffers_.find(tracing_session->buffers_index[buf_idx]);
2500
300
    if (tbuf_iter == buffers_.end()) {
2501
0
      PERFETTO_DFATAL("Buffer not found.");
2502
0
      continue;
2503
0
    }
2504
300
    TraceBuffer& tbuf = *tbuf_iter->second;
2505
300
    tbuf.BeginRead();
2506
600
    while (!did_hit_threshold) {
2507
600
      TracePacket packet;
2508
600
      TraceBuffer::PacketSequenceProperties sequence_properties{};
2509
600
      bool previous_packet_dropped;
2510
600
      if (!tbuf.ReadNextTracePacket(&packet, &sequence_properties,
2511
600
                                    &previous_packet_dropped)) {
2512
300
        break;
2513
300
      }
2514
300
      packet.set_buffer_index_for_stats(static_cast<uint32_t>(buf_idx));
2515
300
      PERFETTO_DCHECK(sequence_properties.producer_id_trusted != 0);
2516
300
      PERFETTO_DCHECK(sequence_properties.writer_id != 0);
2517
300
      PERFETTO_DCHECK(sequence_properties.client_identity_trusted.has_uid());
2518
      // Not checking sequence_properties.client_identity_trusted.has_pid():
2519
      // it is false if the platform doesn't support it.
2520
2521
300
      PERFETTO_DCHECK(packet.size() > 0);
2522
300
      if (!PacketStreamValidator::Validate(packet.slices())) {
2523
0
        tracing_session->invalid_packets++;
2524
0
        PERFETTO_DLOG("Dropping invalid packet");
2525
0
        continue;
2526
0
      }
2527
2528
      // Append a slice with the trusted field data. This can't be spoofed
2529
      // because above we validated that the existing slices don't contain any
2530
      // trusted fields. For added safety we append instead of prepending
2531
      // because according to protobuf semantics, if the same field is
2532
      // encountered multiple times the last instance takes priority. Note that
2533
      // truncated packets are also rejected, so the producer can't give us a
2534
      // partial packet (e.g., a truncated string) which only becomes valid when
2535
      // the trusted data is appended here.
2536
300
      Slice slice = Slice::Allocate(32);
2537
300
      protozero::StaticBuffered<protos::pbzero::TracePacket> trusted_packet(
2538
300
          slice.own_data(), slice.size);
2539
300
      const auto& client_identity_trusted =
2540
300
          sequence_properties.client_identity_trusted;
2541
300
      trusted_packet->set_trusted_uid(
2542
300
          static_cast<int32_t>(client_identity_trusted.uid()));
2543
300
      trusted_packet->set_trusted_packet_sequence_id(
2544
300
          tracing_session->GetPacketSequenceID(
2545
300
              client_identity_trusted.machine_id(),
2546
300
              sequence_properties.producer_id_trusted,
2547
300
              sequence_properties.writer_id));
2548
300
      if (client_identity_trusted.has_pid()) {
2549
        // Not supported on all platforms.
2550
300
        trusted_packet->set_trusted_pid(
2551
300
            static_cast<int32_t>(client_identity_trusted.pid()));
2552
300
      }
2553
300
      if (client_identity_trusted.has_non_default_machine_id()) {
2554
0
        trusted_packet->set_machine_id(client_identity_trusted.machine_id());
2555
0
      }
2556
300
      if (previous_packet_dropped)
2557
300
        trusted_packet->set_previous_packet_dropped(previous_packet_dropped);
2558
300
      slice.size = trusted_packet.Finalize();
2559
300
      packet.AddSlice(std::move(slice));
2560
2561
      // Append the packet (inclusive of the trusted uid) to |packets|.
2562
300
      packets_bytes += packet.size();
2563
300
      did_hit_threshold = packets_bytes >= threshold;
2564
300
      packets.emplace_back(std::move(packet));
2565
300
    }  // for(packets...)
2566
300
  }    // for(buffers...)
2567
2568
300
  *has_more = did_hit_threshold;
2569
2570
  // Only emit the "read complete" lifetime event when there is no more trace
2571
  // data available to read. These events are used as safe points to limit
2572
  // sorting in trace processor: the code shouldn't emit the event unless the
2573
  // buffers are empty.
2574
300
  if (!*has_more && !tracing_session->config.builtin_data_sources()
2575
300
                         .disable_service_events()) {
2576
    // We don't bother snapshotting clocks here because we wouldn't be able to
2577
    // emit it and we shouldn't have significant drift from the last snapshot in
2578
    // any case.
2579
300
    SnapshotLifecycleEvent(tracing_session,
2580
300
                           protos::pbzero::TracingServiceEvent::
2581
300
                               kReadTracingBuffersCompletedFieldNumber,
2582
300
                           false /* snapshot_clocks */);
2583
300
    EmitLifecycleEvents(tracing_session, &packets);
2584
300
  }
2585
2586
  // Only emit the stats when there is no more trace data is available to read.
2587
  // That way, any problems that occur while reading from the buffers are
2588
  // reflected in the emitted stats. This is particularly important for use
2589
  // cases where ReadBuffers is only ever called after the tracing session is
2590
  // stopped.
2591
300
  if (!*has_more && tracing_session->should_emit_stats) {
2592
300
    EmitStats(tracing_session, &packets);
2593
300
    tracing_session->should_emit_stats = false;
2594
300
  }
2595
2596
300
  MaybeFilterPackets(tracing_session, &packets);
2597
2598
300
  MaybeCompressPackets(tracing_session, &packets);
2599
2600
300
  if (!*has_more) {
2601
    // We've observed some extremely high memory usage by scudo after
2602
    // MaybeFilterPackets in the past. The original bug (b/195145848) is fixed
2603
    // now, but this code asks scudo to release memory just in case.
2604
300
    base::MaybeReleaseAllocatorMemToOS();
2605
300
  }
2606
2607
300
  return packets;
2608
300
}
2609
2610
void TracingServiceImpl::MaybeFilterPackets(TracingSession* tracing_session,
2611
300
                                            std::vector<TracePacket>* packets) {
2612
  // If the tracing session specified a filter, run all packets through the
2613
  // filter and replace them with the filter results.
2614
  // The process below mantains the cardinality of input packets. Even if an
2615
  // entire packet is filtered out, we emit a zero-sized TracePacket proto. That
2616
  // makes debugging and reasoning about the trace stats easier.
2617
  // This place swaps the contents of each |packets| entry in place.
2618
300
  if (!tracing_session->trace_filter) {
2619
300
    return;
2620
300
  }
2621
0
  protozero::MessageFilter& trace_filter = *tracing_session->trace_filter;
2622
  // The filter root should be reset from protos.Trace to protos.TracePacket
2623
  // by the earlier call to SetFilterRoot() in EnableTracing().
2624
0
  PERFETTO_DCHECK(trace_filter.config().root_msg_index() != 0);
2625
0
  std::vector<protozero::MessageFilter::InputSlice> filter_input;
2626
0
  auto start = clock_->GetWallTimeNs();
2627
0
  for (TracePacket& packet : *packets) {
2628
0
    const auto& packet_slices = packet.slices();
2629
0
    const size_t input_packet_size = packet.size();
2630
0
    filter_input.clear();
2631
0
    filter_input.resize(packet_slices.size());
2632
0
    ++tracing_session->filter_input_packets;
2633
0
    tracing_session->filter_input_bytes += input_packet_size;
2634
0
    for (size_t i = 0; i < packet_slices.size(); ++i)
2635
0
      filter_input[i] = {packet_slices[i].start, packet_slices[i].size};
2636
0
    auto filtered_packet = trace_filter.FilterMessageFragments(
2637
0
        &filter_input[0], filter_input.size());
2638
2639
    // Replace the packet in-place with the filtered one (unless failed).
2640
0
    std::optional<uint32_t> maybe_buffer_idx = packet.buffer_index_for_stats();
2641
0
    packet = TracePacket();
2642
0
    if (filtered_packet.error) {
2643
0
      ++tracing_session->filter_errors;
2644
0
      PERFETTO_DLOG("Trace packet filtering failed @ packet %" PRIu64,
2645
0
                    tracing_session->filter_input_packets);
2646
0
      continue;
2647
0
    }
2648
0
    tracing_session->filter_output_bytes += filtered_packet.size;
2649
0
    if (maybe_buffer_idx.has_value()) {
2650
      // Keep the per-buffer stats updated. Also propagate the
2651
      // buffer_index_for_stats in the output packet to allow accounting by
2652
      // other parts of the ReadBuffer pipeline.
2653
0
      uint32_t buffer_idx = maybe_buffer_idx.value();
2654
0
      packet.set_buffer_index_for_stats(buffer_idx);
2655
0
      auto& vec = tracing_session->filter_bytes_discarded_per_buffer;
2656
0
      if (static_cast<size_t>(buffer_idx) >= vec.size())
2657
0
        vec.resize(buffer_idx + 1);
2658
0
      PERFETTO_DCHECK(input_packet_size >= filtered_packet.size);
2659
0
      size_t bytes_filtered_out = input_packet_size - filtered_packet.size;
2660
0
      vec[buffer_idx] += bytes_filtered_out;
2661
0
    }
2662
0
    AppendOwnedSlicesToPacket(std::move(filtered_packet.data),
2663
0
                              filtered_packet.size, kMaxTracePacketSliceSize,
2664
0
                              &packet);
2665
0
  }
2666
0
  auto end = clock_->GetWallTimeNs();
2667
0
  tracing_session->filter_time_taken_ns +=
2668
0
      static_cast<uint64_t>((end - start).count());
2669
0
}
2670
2671
void TracingServiceImpl::MaybeCompressPackets(
2672
    TracingSession* tracing_session,
2673
300
    std::vector<TracePacket>* packets) {
2674
300
  if (!tracing_session->compress_deflate) {
2675
300
    return;
2676
300
  }
2677
2678
0
  init_opts_.compressor_fn(packets);
2679
0
}
2680
2681
bool TracingServiceImpl::WriteIntoFile(TracingSession* tracing_session,
2682
0
                                       std::vector<TracePacket> packets) {
2683
0
  if (!tracing_session->write_into_file) {
2684
0
    return false;
2685
0
  }
2686
0
  const uint64_t max_size = tracing_session->max_file_size_bytes
2687
0
                                ? tracing_session->max_file_size_bytes
2688
0
                                : std::numeric_limits<size_t>::max();
2689
2690
0
  size_t total_slices = 0;
2691
0
  for (const TracePacket& packet : packets) {
2692
0
    total_slices += packet.slices().size();
2693
0
  }
2694
  // When writing into a file, the file should look like a root trace.proto
2695
  // message. Each packet should be prepended with a proto preamble stating
2696
  // its field id (within trace.proto) and size. Hence the addition below.
2697
0
  const size_t max_iovecs = total_slices + packets.size();
2698
2699
0
  size_t num_iovecs = 0;
2700
0
  bool stop_writing_into_file = false;
2701
0
  std::unique_ptr<struct iovec[]> iovecs(new struct iovec[max_iovecs]);
2702
0
  size_t num_iovecs_at_last_packet = 0;
2703
0
  uint64_t bytes_about_to_be_written = 0;
2704
0
  for (TracePacket& packet : packets) {
2705
0
    std::tie(iovecs[num_iovecs].iov_base, iovecs[num_iovecs].iov_len) =
2706
0
        packet.GetProtoPreamble();
2707
0
    bytes_about_to_be_written += iovecs[num_iovecs].iov_len;
2708
0
    num_iovecs++;
2709
0
    for (const Slice& slice : packet.slices()) {
2710
      // writev() doesn't change the passed pointer. However, struct iovec
2711
      // take a non-const ptr because it's the same struct used by readv().
2712
      // Hence the const_cast here.
2713
0
      char* start = static_cast<char*>(const_cast<void*>(slice.start));
2714
0
      bytes_about_to_be_written += slice.size;
2715
0
      iovecs[num_iovecs++] = {start, slice.size};
2716
0
    }
2717
2718
0
    if (tracing_session->bytes_written_into_file + bytes_about_to_be_written >=
2719
0
        max_size) {
2720
0
      stop_writing_into_file = true;
2721
0
      num_iovecs = num_iovecs_at_last_packet;
2722
0
      break;
2723
0
    }
2724
2725
0
    num_iovecs_at_last_packet = num_iovecs;
2726
0
  }
2727
0
  PERFETTO_DCHECK(num_iovecs <= max_iovecs);
2728
0
  int fd = *tracing_session->write_into_file;
2729
2730
0
  uint64_t total_wr_size = 0;
2731
2732
  // writev() can take at most IOV_MAX entries per call. Batch them.
2733
0
  constexpr size_t kIOVMax = IOV_MAX;
2734
0
  for (size_t i = 0; i < num_iovecs; i += kIOVMax) {
2735
0
    int iov_batch_size = static_cast<int>(std::min(num_iovecs - i, kIOVMax));
2736
0
    ssize_t wr_size = PERFETTO_EINTR(writev(fd, &iovecs[i], iov_batch_size));
2737
0
    if (wr_size <= 0) {
2738
0
      PERFETTO_PLOG("writev() failed");
2739
0
      stop_writing_into_file = true;
2740
0
      break;
2741
0
    }
2742
0
    total_wr_size += static_cast<size_t>(wr_size);
2743
0
  }
2744
2745
0
  tracing_session->bytes_written_into_file += total_wr_size;
2746
2747
0
  PERFETTO_DLOG("Draining into file, written: %" PRIu64 " KB, stop: %d",
2748
0
                (total_wr_size + 1023) / 1024, stop_writing_into_file);
2749
0
  return stop_writing_into_file;
2750
0
}
2751
2752
300
void TracingServiceImpl::FreeBuffers(TracingSessionID tsid) {
2753
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
2754
300
  PERFETTO_DLOG("Freeing buffers for session %" PRIu64, tsid);
2755
300
  TracingSession* tracing_session = GetTracingSession(tsid);
2756
300
  if (!tracing_session) {
2757
0
    PERFETTO_DLOG("FreeBuffers() failed, invalid session ID %" PRIu64, tsid);
2758
0
    return;  // TODO(primiano): signal failure?
2759
0
  }
2760
300
  DisableTracing(tsid, /*disable_immediately=*/true);
2761
2762
300
  PERFETTO_DCHECK(tracing_session->AllDataSourceInstancesStopped());
2763
300
  tracing_session->data_source_instances.clear();
2764
2765
300
  for (auto& producer_entry : producers_) {
2766
0
    ProducerEndpointImpl* producer = producer_entry.second;
2767
0
    producer->OnFreeBuffers(tracing_session->buffers_index);
2768
0
  }
2769
2770
300
  for (BufferID buffer_id : tracing_session->buffers_index) {
2771
300
    buffer_ids_.Free(buffer_id);
2772
300
    PERFETTO_DCHECK(buffers_.count(buffer_id) == 1);
2773
300
    buffers_.erase(buffer_id);
2774
300
  }
2775
300
  bool notify_traceur =
2776
300
      tracing_session->config.notify_traceur() &&
2777
0
      tracing_session->state != TracingSession::CLONED_READ_ONLY;
2778
300
  bool is_long_trace =
2779
300
      (tracing_session->config.write_into_file() &&
2780
0
       tracing_session->config.file_write_period_ms() < kMillisPerDay);
2781
300
  auto pending_clones = std::move(tracing_session->pending_clones);
2782
300
  tracing_sessions_.erase(tsid);
2783
300
  tracing_session = nullptr;
2784
300
  UpdateMemoryGuardrail();
2785
2786
300
  for (const auto& id_to_clone_op : pending_clones) {
2787
0
    const PendingClone& clone_op = id_to_clone_op.second;
2788
0
    if (clone_op.weak_consumer) {
2789
0
      weak_runner_.task_runner()->PostTask(
2790
0
          [weak_consumer = clone_op.weak_consumer] {
2791
0
            if (weak_consumer) {
2792
0
              weak_consumer->consumer_->OnSessionCloned(
2793
0
                  {false, "Original session ended", {}});
2794
0
            }
2795
0
          });
2796
0
    }
2797
0
  }
2798
2799
300
  PERFETTO_LOG("Tracing session %" PRIu64 " ended, total sessions:%zu", tsid,
2800
300
               tracing_sessions_.size());
2801
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && \
2802
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
2803
  if (notify_traceur && is_long_trace) {
2804
    PERFETTO_LAZY_LOAD(android_internal::NotifyTraceSessionEnded, notify_fn);
2805
    if (!notify_fn || !notify_fn(/*session_stolen=*/false))
2806
      PERFETTO_ELOG("Failed to notify Traceur long tracing has ended");
2807
  }
2808
#else
2809
300
  base::ignore_result(notify_traceur);
2810
300
  base::ignore_result(is_long_trace);
2811
300
#endif
2812
300
}
2813
2814
void TracingServiceImpl::RegisterDataSource(ProducerID producer_id,
2815
300
                                            const DataSourceDescriptor& desc) {
2816
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
2817
300
  if (desc.name().empty()) {
2818
0
    PERFETTO_DLOG("Received RegisterDataSource() with empty name");
2819
0
    return;
2820
0
  }
2821
2822
300
  ProducerEndpointImpl* producer = GetProducer(producer_id);
2823
300
  if (!producer) {
2824
0
    PERFETTO_DFATAL("Producer not found.");
2825
0
    return;
2826
0
  }
2827
2828
  // Check that the producer doesn't register two data sources with the same ID.
2829
  // Note that we tolerate |id| == 0 because until Android T / v22 the |id|
2830
  // field didn't exist.
2831
300
  for (const auto& kv : data_sources_) {
2832
0
    if (desc.id() && kv.second.producer_id == producer_id &&
2833
0
        kv.second.descriptor.id() == desc.id()) {
2834
0
      PERFETTO_ELOG(
2835
0
          "Failed to register data source \"%s\". A data source with the same "
2836
0
          "id %" PRIu64 " (name=\"%s\") is already registered for producer %d",
2837
0
          desc.name().c_str(), desc.id(), kv.second.descriptor.name().c_str(),
2838
0
          producer_id);
2839
0
      return;
2840
0
    }
2841
0
  }
2842
2843
300
  PERFETTO_DLOG("Producer %" PRIu16 " registered data source \"%s\"",
2844
300
                producer_id, desc.name().c_str());
2845
2846
300
  auto reg_ds = data_sources_.emplace(desc.name(),
2847
300
                                      RegisteredDataSource{producer_id, desc});
2848
2849
  // If there are existing tracing sessions, we need to check if the new
2850
  // data source is enabled by any of them.
2851
300
  for (auto& iter : tracing_sessions_) {
2852
213
    TracingSession& tracing_session = iter.second;
2853
213
    if (tracing_session.state != TracingSession::STARTED &&
2854
0
        tracing_session.state != TracingSession::CONFIGURED) {
2855
0
      continue;
2856
0
    }
2857
2858
213
    TraceConfig::ProducerConfig producer_config;
2859
213
    for (const auto& config : tracing_session.config.producers()) {
2860
0
      if (producer->name_ == config.producer_name()) {
2861
0
        producer_config = config;
2862
0
        break;
2863
0
      }
2864
0
    }
2865
213
    for (const TraceConfig::DataSource& cfg_data_source :
2866
213
         tracing_session.config.data_sources()) {
2867
213
      if (cfg_data_source.config().name() != desc.name())
2868
0
        continue;
2869
213
      DataSourceInstance* ds_inst = SetupDataSource(
2870
213
          cfg_data_source, producer_config, reg_ds->second, &tracing_session);
2871
213
      if (ds_inst && tracing_session.state == TracingSession::STARTED)
2872
213
        StartDataSourceInstance(producer, &tracing_session, ds_inst);
2873
213
    }
2874
213
  }  // for(iter : tracing_sessions_)
2875
300
}
2876
2877
void TracingServiceImpl::UpdateDataSource(
2878
    ProducerID producer_id,
2879
0
    const DataSourceDescriptor& new_desc) {
2880
0
  if (new_desc.id() == 0) {
2881
0
    PERFETTO_ELOG("UpdateDataSource() must have a non-zero id");
2882
0
    return;
2883
0
  }
2884
2885
  // If this producer has already registered a matching descriptor name and id,
2886
  // just update the descriptor.
2887
0
  RegisteredDataSource* data_source = nullptr;
2888
0
  auto range = data_sources_.equal_range(new_desc.name());
2889
0
  for (auto it = range.first; it != range.second; ++it) {
2890
0
    if (it->second.producer_id == producer_id &&
2891
0
        it->second.descriptor.id() == new_desc.id()) {
2892
0
      data_source = &it->second;
2893
0
      break;
2894
0
    }
2895
0
  }
2896
2897
0
  if (!data_source) {
2898
0
    PERFETTO_ELOG(
2899
0
        "UpdateDataSource() failed, could not find an existing data source "
2900
0
        "with name=\"%s\" id=%" PRIu64,
2901
0
        new_desc.name().c_str(), new_desc.id());
2902
0
    return;
2903
0
  }
2904
2905
0
  data_source->descriptor = new_desc;
2906
0
}
2907
2908
void TracingServiceImpl::StopDataSourceInstance(ProducerEndpointImpl* producer,
2909
                                                TracingSession* tracing_session,
2910
                                                DataSourceInstance* instance,
2911
300
                                                bool disable_immediately) {
2912
300
  const DataSourceInstanceID ds_inst_id = instance->instance_id;
2913
300
  if (producer->IsAndroidProcessFrozen()) {
2914
0
    PERFETTO_DLOG(
2915
0
        "skipping waiting of data source \"%s\" on producer \"%s\" (pid=%u) "
2916
0
        "because it is frozen",
2917
0
        instance->data_source_name.c_str(), producer->name_.c_str(),
2918
0
        producer->pid());
2919
0
    disable_immediately = true;
2920
0
  }
2921
300
  if (instance->will_notify_on_stop && !disable_immediately) {
2922
0
    instance->state = DataSourceInstance::STOPPING;
2923
300
  } else {
2924
300
    instance->state = DataSourceInstance::STOPPED;
2925
300
  }
2926
300
  if (tracing_session->consumer_maybe_null) {
2927
300
    tracing_session->consumer_maybe_null->OnDataSourceInstanceStateChange(
2928
300
        *producer, *instance);
2929
300
  }
2930
300
  producer->StopDataSource(ds_inst_id);
2931
300
}
2932
2933
void TracingServiceImpl::UnregisterDataSource(ProducerID producer_id,
2934
300
                                              const std::string& name) {
2935
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
2936
300
  PERFETTO_DLOG("Producer %" PRIu16 " unregistered data source \"%s\"",
2937
300
                producer_id, name.c_str());
2938
300
  PERFETTO_CHECK(producer_id);
2939
300
  ProducerEndpointImpl* producer = GetProducer(producer_id);
2940
300
  PERFETTO_DCHECK(producer);
2941
300
  for (auto& kv : tracing_sessions_) {
2942
300
    auto& ds_instances = kv.second.data_source_instances;
2943
300
    bool removed = false;
2944
600
    for (auto it = ds_instances.begin(); it != ds_instances.end();) {
2945
300
      if (it->first == producer_id && it->second.data_source_name == name) {
2946
300
        DataSourceInstanceID ds_inst_id = it->second.instance_id;
2947
300
        if (it->second.state != DataSourceInstance::STOPPED) {
2948
300
          if (it->second.state != DataSourceInstance::STOPPING) {
2949
300
            StopDataSourceInstance(producer, &kv.second, &it->second,
2950
300
                                   /* disable_immediately = */ false);
2951
300
          }
2952
2953
          // Mark the instance as stopped immediately, since we are
2954
          // unregistering it below.
2955
          //
2956
          //  The StopDataSourceInstance above might have set the state to
2957
          //  STOPPING so this condition isn't an else.
2958
300
          if (it->second.state == DataSourceInstance::STOPPING)
2959
0
            NotifyDataSourceStopped(producer_id, ds_inst_id);
2960
300
        }
2961
300
        it = ds_instances.erase(it);
2962
300
        removed = true;
2963
300
      } else {
2964
0
        ++it;
2965
0
      }
2966
300
    }  // for (data_source_instances)
2967
300
    if (removed)
2968
300
      MaybeNotifyAllDataSourcesStarted(&kv.second);
2969
300
  }  // for (tracing_session)
2970
2971
300
  for (auto it = data_sources_.begin(); it != data_sources_.end(); ++it) {
2972
300
    if (it->second.producer_id == producer_id &&
2973
300
        it->second.descriptor.name() == name) {
2974
300
      data_sources_.erase(it);
2975
300
      return;
2976
300
    }
2977
300
  }
2978
2979
300
  PERFETTO_DFATAL(
2980
0
      "Tried to unregister a non-existent data source \"%s\" for "
2981
0
      "producer %" PRIu16,
2982
0
      name.c_str(), producer_id);
2983
0
}
2984
2985
bool TracingServiceImpl::IsInitiatorPrivileged(
2986
300
    const TracingSession& tracing_session) {
2987
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
2988
  if (tracing_session.consumer_uid == 1066 /* AID_STATSD */ &&
2989
      tracing_session.config.statsd_metadata().triggering_config_uid() !=
2990
          2000 /* AID_SHELL */
2991
      && tracing_session.config.statsd_metadata().triggering_config_uid() !=
2992
             0 /* AID_ROOT */) {
2993
    // StatsD can be triggered either by shell, root or an app that has DUMP and
2994
    // USAGE_STATS permission. When triggered by shell or root, we do not want
2995
    // to consider the trace a trusted system trace, as it was initiated by the
2996
    // user. Otherwise, it has to come from an app with DUMP and
2997
    // PACKAGE_USAGE_STATS, which has to be preinstalled and trusted by the
2998
    // system.
2999
    // Check for shell / root: https://bit.ly/3b7oZNi
3000
    // Check for DUMP or PACKAGE_USAGE_STATS: https://bit.ly/3ep0NrR
3001
    return true;
3002
  }
3003
  if (tracing_session.consumer_uid == 1000 /* AID_SYSTEM */) {
3004
    // AID_SYSTEM is considered a privileged initiator so that system_server can
3005
    // profile apps that are not profileable by shell. Other AID_SYSTEM
3006
    // processes are not allowed by SELinux to connect to the consumer socket or
3007
    // to exec perfetto.
3008
    return true;
3009
  }
3010
#else
3011
300
  base::ignore_result(tracing_session);
3012
300
#endif
3013
300
  return false;
3014
300
}
3015
3016
TracingServiceImpl::DataSourceInstance* TracingServiceImpl::SetupDataSource(
3017
    const TraceConfig::DataSource& cfg_data_source,
3018
    const TraceConfig::ProducerConfig& producer_config,
3019
    const RegisteredDataSource& data_source,
3020
300
    TracingSession* tracing_session) {
3021
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
3022
300
  ProducerEndpointImpl* producer = GetProducer(data_source.producer_id);
3023
300
  PERFETTO_DCHECK(producer);
3024
  // An existing producer that is not ftrace could have registered itself as
3025
  // ftrace, we must not enable it in that case.
3026
300
  if (lockdown_mode_ && producer->uid() != uid_) {
3027
0
    PERFETTO_DLOG("Lockdown mode: not enabling producer %hu", producer->id_);
3028
0
    return nullptr;
3029
0
  }
3030
  // TODO(primiano): Add tests for registration ordering (data sources vs
3031
  // consumers).
3032
300
  if (!NameMatchesFilter(producer->name_,
3033
300
                         cfg_data_source.producer_name_filter(),
3034
300
                         cfg_data_source.producer_name_regex_filter())) {
3035
0
    PERFETTO_DLOG("Data source: %s is filtered out for producer: %s",
3036
0
                  cfg_data_source.config().name().c_str(),
3037
0
                  producer->name_.c_str());
3038
0
    return nullptr;
3039
0
  }
3040
3041
300
  auto relative_buffer_id = cfg_data_source.config().target_buffer();
3042
300
  if (relative_buffer_id >= tracing_session->num_buffers()) {
3043
0
    PERFETTO_LOG(
3044
0
        "The TraceConfig for DataSource %s specified a target_buffer out of "
3045
0
        "bound (%u). Skipping it.",
3046
0
        cfg_data_source.config().name().c_str(), relative_buffer_id);
3047
0
    return nullptr;
3048
0
  }
3049
3050
  // Create a copy of the DataSourceConfig specified in the trace config. This
3051
  // will be passed to the producer after translating the |target_buffer| id.
3052
  // The |target_buffer| parameter passed by the consumer in the trace config is
3053
  // relative to the buffers declared in the same trace config. This has to be
3054
  // translated to the global BufferID before passing it to the producers, which
3055
  // don't know anything about tracing sessions and consumers.
3056
3057
300
  DataSourceInstanceID inst_id = ++last_data_source_instance_id_;
3058
300
  auto insert_iter = tracing_session->data_source_instances.emplace(
3059
300
      std::piecewise_construct,  //
3060
300
      std::forward_as_tuple(producer->id_),
3061
300
      std::forward_as_tuple(
3062
300
          inst_id,
3063
300
          cfg_data_source.config(),  //  Deliberate copy.
3064
300
          data_source.descriptor.name(),
3065
300
          data_source.descriptor.will_notify_on_start(),
3066
300
          data_source.descriptor.will_notify_on_stop(),
3067
300
          data_source.descriptor.handles_incremental_state_clear(),
3068
300
          data_source.descriptor.no_flush()));
3069
300
  DataSourceInstance* ds_instance = &insert_iter->second;
3070
3071
  // New data source instance starts out in CONFIGURED state.
3072
300
  if (tracing_session->consumer_maybe_null) {
3073
300
    tracing_session->consumer_maybe_null->OnDataSourceInstanceStateChange(
3074
300
        *producer, *ds_instance);
3075
300
  }
3076
3077
300
  DataSourceConfig& ds_config = ds_instance->config;
3078
300
  ds_config.set_trace_duration_ms(tracing_session->config.duration_ms());
3079
3080
  // Rationale for `if (prefer) set_prefer(true)`, rather than `set(prefer)`:
3081
  // ComputeStartupConfigHash() in tracing_muxer_impl.cc compares hashes of the
3082
  // DataSourceConfig and expects to know (and clear) the fields generated by
3083
  // the tracing service. Unconditionally adding a new field breaks backward
3084
  // compatibility of startup tracing with older SDKs, because the serialization
3085
  // also propagates unkonwn fields, breaking the hash matching check.
3086
300
  if (tracing_session->config.prefer_suspend_clock_for_duration())
3087
0
    ds_config.set_prefer_suspend_clock_for_duration(true);
3088
3089
300
  ds_config.set_stop_timeout_ms(tracing_session->data_source_stop_timeout_ms());
3090
300
  ds_config.set_enable_extra_guardrails(
3091
300
      tracing_session->config.enable_extra_guardrails());
3092
300
  if (IsInitiatorPrivileged(*tracing_session)) {
3093
0
    ds_config.set_session_initiator(
3094
0
        DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM);
3095
300
  } else {
3096
    // Unset in case the consumer set it.
3097
    // We need to be able to trust this field.
3098
300
    ds_config.set_session_initiator(
3099
300
        DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED);
3100
300
  }
3101
300
  ds_config.set_tracing_session_id(tracing_session->id);
3102
300
  BufferID global_id = tracing_session->buffers_index[relative_buffer_id];
3103
300
  PERFETTO_DCHECK(global_id);
3104
300
  ds_config.set_target_buffer(global_id);
3105
3106
300
  PERFETTO_DLOG("Setting up data source %s with target buffer %" PRIu16,
3107
300
                ds_config.name().c_str(), global_id);
3108
300
  if (!producer->shared_memory()) {
3109
    // Determine the SMB page size. Must be an integer multiple of 4k.
3110
    // As for the SMB size below, the decision tree is as follows:
3111
    // 1. Give priority to what is defined in the trace config.
3112
    // 2. If unset give priority to the hint passed by the producer.
3113
    // 3. Keep within bounds and ensure it's a multiple of 4k.
3114
300
    size_t page_size = producer_config.page_size_kb() * 1024;
3115
300
    if (page_size == 0)
3116
300
      page_size = producer->shmem_page_size_hint_bytes_;
3117
3118
    // Determine the SMB size. Must be an integer multiple of the SMB page size.
3119
    // The decision tree is as follows:
3120
    // 1. Give priority to what defined in the trace config.
3121
    // 2. If unset give priority to the hint passed by the producer.
3122
    // 3. Keep within bounds and ensure it's a multiple of the page size.
3123
300
    size_t shm_size = producer_config.shm_size_kb() * 1024;
3124
300
    if (shm_size == 0)
3125
300
      shm_size = producer->shmem_size_hint_bytes_;
3126
3127
300
    auto valid_sizes = EnsureValidShmSizes(shm_size, page_size);
3128
300
    if (valid_sizes != std::tie(shm_size, page_size)) {
3129
300
      PERFETTO_DLOG(
3130
300
          "Invalid configured SMB sizes: shm_size %zu page_size %zu. Falling "
3131
300
          "back to shm_size %zu page_size %zu.",
3132
300
          shm_size, page_size, std::get<0>(valid_sizes),
3133
300
          std::get<1>(valid_sizes));
3134
300
    }
3135
300
    std::tie(shm_size, page_size) = valid_sizes;
3136
3137
    // TODO(primiano): right now Create() will suicide in case of OOM if the
3138
    // mmap fails. We should instead gracefully fail the request and tell the
3139
    // client to go away.
3140
300
    PERFETTO_DLOG("Creating SMB of %zu KB for producer \"%s\"", shm_size / 1024,
3141
300
                  producer->name_.c_str());
3142
300
    auto shared_memory = shm_factory_->CreateSharedMemory(shm_size);
3143
300
    producer->SetupSharedMemory(std::move(shared_memory), page_size,
3144
300
                                /*provided_by_producer=*/false);
3145
300
  }
3146
300
  producer->SetupDataSource(inst_id, ds_config);
3147
300
  return ds_instance;
3148
300
}
3149
3150
// Note: all the fields % *_trusted ones are untrusted, as in, the Producer
3151
// might be lying / returning garbage contents. |src| and |size| can be trusted
3152
// in terms of being a valid pointer, but not the contents.
3153
void TracingServiceImpl::CopyProducerPageIntoLogBuffer(
3154
    ProducerID producer_id_trusted,
3155
    const ClientIdentity& client_identity_trusted,
3156
    WriterID writer_id,
3157
    ChunkID chunk_id,
3158
    BufferID buffer_id,
3159
    uint16_t num_fragments,
3160
    uint8_t chunk_flags,
3161
    bool chunk_complete,
3162
    const uint8_t* src,
3163
44.6k
    size_t size) {
3164
44.6k
  PERFETTO_DCHECK_THREAD(thread_checker_);
3165
3166
44.6k
  ProducerEndpointImpl* producer = GetProducer(producer_id_trusted);
3167
44.6k
  if (!producer) {
3168
0
    PERFETTO_DFATAL("Producer not found.");
3169
0
    chunks_discarded_++;
3170
0
    return;
3171
0
  }
3172
3173
44.6k
  TraceBuffer* buf = GetBufferByID(buffer_id);
3174
44.6k
  if (!buf) {
3175
0
    PERFETTO_DLOG("Could not find target buffer %" PRIu16
3176
0
                  " for producer %" PRIu16,
3177
0
                  buffer_id, producer_id_trusted);
3178
0
    chunks_discarded_++;
3179
0
    return;
3180
0
  }
3181
3182
  // Verify that the producer is actually allowed to write into the target
3183
  // buffer specified in the request. This prevents a malicious producer from
3184
  // injecting data into a log buffer that belongs to a tracing session the
3185
  // producer is not part of.
3186
44.6k
  if (!producer->is_allowed_target_buffer(buffer_id)) {
3187
0
    PERFETTO_ELOG("Producer %" PRIu16
3188
0
                  " tried to write into forbidden target buffer %" PRIu16,
3189
0
                  producer_id_trusted, buffer_id);
3190
0
    PERFETTO_DFATAL("Forbidden target buffer");
3191
0
    chunks_discarded_++;
3192
0
    return;
3193
0
  }
3194
3195
  // If the writer was registered by the producer, it should only write into the
3196
  // buffer it was registered with.
3197
44.6k
  std::optional<BufferID> associated_buffer =
3198
44.6k
      producer->buffer_id_for_writer(writer_id);
3199
44.6k
  if (associated_buffer && *associated_buffer != buffer_id) {
3200
0
    PERFETTO_ELOG("Writer %" PRIu16 " of producer %" PRIu16
3201
0
                  " was registered to write into target buffer %" PRIu16
3202
0
                  ", but tried to write into buffer %" PRIu16,
3203
0
                  writer_id, producer_id_trusted, *associated_buffer,
3204
0
                  buffer_id);
3205
0
    PERFETTO_DFATAL("Wrong target buffer");
3206
0
    chunks_discarded_++;
3207
0
    return;
3208
0
  }
3209
3210
44.6k
  buf->CopyChunkUntrusted(producer_id_trusted, client_identity_trusted,
3211
44.6k
                          writer_id, chunk_id, num_fragments, chunk_flags,
3212
44.6k
                          chunk_complete, src, size);
3213
44.6k
}
3214
3215
void TracingServiceImpl::ApplyChunkPatches(
3216
    ProducerID producer_id_trusted,
3217
1.75k
    const std::vector<CommitDataRequest::ChunkToPatch>& chunks_to_patch) {
3218
1.75k
  PERFETTO_DCHECK_THREAD(thread_checker_);
3219
3220
1.75k
  for (const auto& chunk : chunks_to_patch) {
3221
0
    const ChunkID chunk_id = static_cast<ChunkID>(chunk.chunk_id());
3222
0
    const WriterID writer_id = static_cast<WriterID>(chunk.writer_id());
3223
0
    TraceBuffer* buf =
3224
0
        GetBufferByID(static_cast<BufferID>(chunk.target_buffer()));
3225
0
    static_assert(std::numeric_limits<ChunkID>::max() == kMaxChunkID,
3226
0
                  "Add a '|| chunk_id > kMaxChunkID' below if this fails");
3227
0
    if (!writer_id || writer_id > kMaxWriterID || !buf) {
3228
      // This can genuinely happen when the trace is stopped. The producers
3229
      // might see the stop signal with some delay and try to keep sending
3230
      // patches left soon after.
3231
0
      PERFETTO_DLOG(
3232
0
          "Received invalid chunks_to_patch request from Producer: %" PRIu16
3233
0
          ", BufferID: %" PRIu32 " ChunkdID: %" PRIu32 " WriterID: %" PRIu16,
3234
0
          producer_id_trusted, chunk.target_buffer(), chunk_id, writer_id);
3235
0
      patches_discarded_ += static_cast<uint64_t>(chunk.patches_size());
3236
0
      continue;
3237
0
    }
3238
3239
    // Note, there's no need to validate that the producer is allowed to write
3240
    // to the specified buffer ID (or that it's the correct buffer ID for a
3241
    // registered TraceWriter). That's because TraceBuffer uses the producer ID
3242
    // and writer ID to look up the chunk to patch. If the producer specifies an
3243
    // incorrect buffer, this lookup will fail and TraceBuffer will ignore the
3244
    // patches. Because the producer ID is trusted, there's also no way for a
3245
    // malicious producer to patch another producer's data.
3246
3247
    // Speculate on the fact that there are going to be a limited amount of
3248
    // patches per request, so we can allocate the |patches| array on the stack.
3249
0
    std::array<TraceBuffer::Patch, 1024> patches;  // Uninitialized.
3250
0
    if (chunk.patches().size() > patches.size()) {
3251
0
      PERFETTO_ELOG("Too many patches (%zu) batched in the same request",
3252
0
                    patches.size());
3253
0
      PERFETTO_DFATAL("Too many patches");
3254
0
      patches_discarded_ += static_cast<uint64_t>(chunk.patches_size());
3255
0
      continue;
3256
0
    }
3257
3258
0
    size_t i = 0;
3259
0
    for (const auto& patch : chunk.patches()) {
3260
0
      const std::string& patch_data = patch.data();
3261
0
      if (patch_data.size() != patches[i].data.size()) {
3262
0
        PERFETTO_ELOG("Received patch from producer: %" PRIu16
3263
0
                      " of unexpected size %zu",
3264
0
                      producer_id_trusted, patch_data.size());
3265
0
        patches_discarded_++;
3266
0
        continue;
3267
0
      }
3268
0
      patches[i].offset_untrusted = patch.offset();
3269
0
      memcpy(&patches[i].data[0], patch_data.data(), patches[i].data.size());
3270
0
      i++;
3271
0
    }
3272
0
    buf->TryPatchChunkContents(producer_id_trusted, writer_id, chunk_id,
3273
0
                               &patches[0], i, chunk.has_more_patches());
3274
0
  }
3275
1.75k
}
3276
3277
TracingServiceImpl::TracingSession* TracingServiceImpl::GetDetachedSession(
3278
    uid_t uid,
3279
0
    const std::string& key) {
3280
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
3281
0
  for (auto& kv : tracing_sessions_) {
3282
0
    TracingSession* session = &kv.second;
3283
0
    if (session->consumer_uid == uid && session->detach_key == key) {
3284
0
      PERFETTO_DCHECK(session->consumer_maybe_null == nullptr);
3285
0
      return session;
3286
0
    }
3287
0
  }
3288
0
  return nullptr;
3289
0
}
3290
3291
TracingServiceImpl::TracingSession* TracingServiceImpl::GetTracingSession(
3292
2.10k
    TracingSessionID tsid) {
3293
2.10k
  PERFETTO_DCHECK_THREAD(thread_checker_);
3294
2.10k
  auto it = tsid ? tracing_sessions_.find(tsid) : tracing_sessions_.end();
3295
2.10k
  if (it == tracing_sessions_.end())
3296
600
    return nullptr;
3297
1.50k
  return &it->second;
3298
2.10k
}
3299
3300
TracingServiceImpl::TracingSession*
3301
TracingServiceImpl::GetTracingSessionByUniqueName(
3302
0
    const std::string& unique_session_name) {
3303
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
3304
0
  if (unique_session_name.empty()) {
3305
0
    return nullptr;
3306
0
  }
3307
0
  for (auto& session_id_and_session : tracing_sessions_) {
3308
0
    TracingSession& session = session_id_and_session.second;
3309
0
    if (session.state == TracingSession::CLONED_READ_ONLY) {
3310
0
      continue;
3311
0
    }
3312
0
    if (session.config.unique_session_name() == unique_session_name) {
3313
0
      return &session;
3314
0
    }
3315
0
  }
3316
0
  return nullptr;
3317
0
}
3318
3319
TracingServiceImpl::TracingSession*
3320
0
TracingServiceImpl::FindTracingSessionWithMaxBugreportScore() {
3321
0
  TracingSession* max_session = nullptr;
3322
0
  for (auto& session_id_and_session : tracing_sessions_) {
3323
0
    auto& session = session_id_and_session.second;
3324
0
    const int32_t score = session.config.bugreport_score();
3325
    // Exclude sessions with 0 (or below) score. By default tracing sessions
3326
    // should NOT be eligible to be attached to bugreports.
3327
0
    if (score <= 0 || session.state != TracingSession::STARTED)
3328
0
      continue;
3329
3330
0
    if (!max_session || score > max_session->config.bugreport_score())
3331
0
      max_session = &session;
3332
0
  }
3333
0
  return max_session;
3334
0
}
3335
3336
300
ProducerID TracingServiceImpl::GetNextProducerID() {
3337
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
3338
300
  PERFETTO_CHECK(producers_.size() < kMaxProducerID);
3339
300
  do {
3340
300
    ++last_producer_id_;
3341
300
  } while (producers_.count(last_producer_id_) || last_producer_id_ == 0);
3342
300
  PERFETTO_DCHECK(last_producer_id_ > 0 && last_producer_id_ <= kMaxProducerID);
3343
300
  return last_producer_id_;
3344
300
}
3345
3346
45.2k
TraceBuffer* TracingServiceImpl::GetBufferByID(BufferID buffer_id) {
3347
45.2k
  auto buf_iter = buffers_.find(buffer_id);
3348
45.2k
  if (buf_iter == buffers_.end())
3349
0
    return nullptr;
3350
45.2k
  return &*buf_iter->second;
3351
45.2k
}
3352
3353
0
void TracingServiceImpl::OnStartTriggersTimeout(TracingSessionID tsid) {
3354
  // Skip entirely the flush if the trace session doesn't exist anymore.
3355
  // This is to prevent misleading error messages to be logged.
3356
  //
3357
  // if the trace has started from the trigger we rely on
3358
  // the |stop_delay_ms| from the trigger so don't flush and
3359
  // disable if we've moved beyond a CONFIGURED state
3360
0
  auto* tracing_session_ptr = GetTracingSession(tsid);
3361
0
  if (tracing_session_ptr &&
3362
0
      tracing_session_ptr->state == TracingSession::CONFIGURED) {
3363
0
    PERFETTO_DLOG("Disabling TracingSession %" PRIu64
3364
0
                  " since no triggers activated.",
3365
0
                  tsid);
3366
    // No data should be returned from ReadBuffers() regardless of if we
3367
    // call FreeBuffers() or DisableTracing(). This is because in
3368
    // STOP_TRACING we need this promise in either case, and using
3369
    // DisableTracing() allows a graceful shutdown. Consumers can follow
3370
    // their normal path and check the buffers through ReadBuffers() and
3371
    // the code won't hang because the tracing session will still be
3372
    // alive just disabled.
3373
0
    DisableTracing(tsid);
3374
0
  }
3375
0
}
3376
3377
1.20k
void TracingServiceImpl::UpdateMemoryGuardrail() {
3378
1.20k
#if PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
3379
1.20k
  uint64_t total_buffer_bytes = 0;
3380
3381
  // Sum up all the shared memory buffers.
3382
1.20k
  for (const auto& id_to_producer : producers_) {
3383
599
    if (id_to_producer.second->shared_memory())
3384
300
      total_buffer_bytes += id_to_producer.second->shared_memory()->size();
3385
599
  }
3386
3387
  // Sum up all the trace buffers.
3388
1.20k
  for (const auto& id_to_buffer : buffers_) {
3389
900
    total_buffer_bytes += id_to_buffer.second->size();
3390
900
  }
3391
3392
  // Sum up all the cloned traced buffers.
3393
1.20k
  for (const auto& id_to_ts : tracing_sessions_) {
3394
900
    const TracingSession& ts = id_to_ts.second;
3395
900
    for (const auto& id_to_clone_op : ts.pending_clones) {
3396
0
      const PendingClone& clone_op = id_to_clone_op.second;
3397
0
      for (const std::unique_ptr<TraceBuffer>& buf : clone_op.buffers) {
3398
0
        if (buf) {
3399
0
          total_buffer_bytes += buf->size();
3400
0
        }
3401
0
      }
3402
0
    }
3403
900
  }
3404
3405
  // Set the guard rail to 32MB + the sum of all the buffers over a 30 second
3406
  // interval.
3407
1.20k
  uint64_t guardrail = base::kWatchdogDefaultMemorySlack + total_buffer_bytes;
3408
1.20k
  base::Watchdog::GetInstance()->SetMemoryLimit(guardrail, 30 * 1000);
3409
1.20k
#endif
3410
1.20k
}
3411
3412
300
void TracingServiceImpl::PeriodicSnapshotTask(TracingSessionID tsid) {
3413
300
  auto* tracing_session = GetTracingSession(tsid);
3414
300
  if (!tracing_session)
3415
0
    return;
3416
300
  if (tracing_session->state != TracingSession::STARTED)
3417
0
    return;
3418
300
  tracing_session->should_emit_sync_marker = true;
3419
300
  tracing_session->should_emit_stats = true;
3420
300
  MaybeSnapshotClocksIntoRingBuffer(tracing_session);
3421
300
}
3422
3423
void TracingServiceImpl::SnapshotLifecycleEvent(TracingSession* tracing_session,
3424
                                                uint32_t field_id,
3425
1.20k
                                                bool snapshot_clocks) {
3426
  // field_id should be an id of a field in TracingServiceEvent.
3427
1.20k
  auto& lifecycle_events = tracing_session->lifecycle_events;
3428
1.20k
  auto event_it =
3429
1.20k
      std::find_if(lifecycle_events.begin(), lifecycle_events.end(),
3430
4.20k
                   [field_id](const TracingSession::LifecycleEvent& event) {
3431
4.20k
                     return event.field_id == field_id;
3432
4.20k
                   });
3433
3434
1.20k
  TracingSession::LifecycleEvent* event;
3435
1.20k
  if (event_it == lifecycle_events.end()) {
3436
1.20k
    lifecycle_events.emplace_back(field_id);
3437
1.20k
    event = &lifecycle_events.back();
3438
1.20k
  } else {
3439
0
    event = &*event_it;
3440
0
  }
3441
3442
  // Snapshot the clocks before capturing the timestamp for the event so we can
3443
  // use this snapshot to resolve the event timestamp if necessary.
3444
1.20k
  if (snapshot_clocks)
3445
600
    MaybeSnapshotClocksIntoRingBuffer(tracing_session);
3446
3447
  // Erase before emplacing to prevent a unncessary doubling of memory if
3448
  // not needed.
3449
1.20k
  if (event->timestamps.size() >= event->max_size) {
3450
0
    event->timestamps.erase_front(1 + event->timestamps.size() -
3451
0
                                  event->max_size);
3452
0
  }
3453
1.20k
  event->timestamps.emplace_back(clock_->GetBootTimeNs().count());
3454
1.20k
}
3455
3456
void TracingServiceImpl::SetSingleLifecycleEvent(
3457
    TracingSession* tracing_session,
3458
    uint32_t field_id,
3459
0
    int64_t boot_timestamp_ns) {
3460
  // field_id should be an id of a field in TracingServiceEvent.
3461
0
  auto& lifecycle_events = tracing_session->lifecycle_events;
3462
0
  auto event_it =
3463
0
      std::find_if(lifecycle_events.begin(), lifecycle_events.end(),
3464
0
                   [field_id](const TracingSession::LifecycleEvent& event) {
3465
0
                     return event.field_id == field_id;
3466
0
                   });
3467
3468
0
  TracingSession::LifecycleEvent* event;
3469
0
  if (event_it == lifecycle_events.end()) {
3470
0
    lifecycle_events.emplace_back(field_id);
3471
0
    event = &lifecycle_events.back();
3472
0
  } else {
3473
0
    event = &*event_it;
3474
0
  }
3475
3476
0
  event->timestamps.clear();
3477
0
  event->timestamps.emplace_back(boot_timestamp_ns);
3478
0
}
3479
3480
void TracingServiceImpl::MaybeSnapshotClocksIntoRingBuffer(
3481
900
    TracingSession* tracing_session) {
3482
900
  if (tracing_session->config.builtin_data_sources()
3483
900
          .disable_clock_snapshotting()) {
3484
0
    return;
3485
0
  }
3486
3487
  // We are making an explicit copy of the latest snapshot (if it exists)
3488
  // because SnapshotClocks reads this data and computes the drift based on its
3489
  // content. If the clock drift is high enough, it will update the contents of
3490
  // |snapshot| and return true. Otherwise, it will return false.
3491
900
  TracingSession::ClockSnapshotData snapshot =
3492
900
      tracing_session->clock_snapshot_ring_buffer.empty()
3493
900
          ? TracingSession::ClockSnapshotData()
3494
900
          : tracing_session->clock_snapshot_ring_buffer.back();
3495
900
  bool did_update = SnapshotClocks(&snapshot);
3496
900
  if (did_update) {
3497
    // This means clocks drifted enough since last snapshot. See the comment
3498
    // in SnapshotClocks.
3499
600
    auto* snapshot_buffer = &tracing_session->clock_snapshot_ring_buffer;
3500
3501
    // Erase before emplacing to prevent a unncessary doubling of memory if
3502
    // not needed.
3503
600
    static constexpr uint32_t kClockSnapshotRingBufferSize = 16;
3504
600
    if (snapshot_buffer->size() >= kClockSnapshotRingBufferSize) {
3505
0
      snapshot_buffer->erase_front(1 + snapshot_buffer->size() -
3506
0
                                   kClockSnapshotRingBufferSize);
3507
0
    }
3508
600
    snapshot_buffer->emplace_back(std::move(snapshot));
3509
600
  }
3510
900
}
3511
3512
// Returns true when the data in |snapshot_data| is updated with the new state
3513
// of the clocks and false otherwise.
3514
bool TracingServiceImpl::SnapshotClocks(
3515
1.20k
    TracingSession::ClockSnapshotData* snapshot_data) {
3516
  // Minimum drift that justifies replacing a prior clock snapshot that hasn't
3517
  // been emitted into the trace yet (see comment below).
3518
1.20k
  static constexpr int64_t kSignificantDriftNs = 10 * 1000 * 1000;  // 10 ms
3519
3520
1.20k
  TracingSession::ClockSnapshotData new_snapshot_data =
3521
1.20k
      base::CaptureClockSnapshots();
3522
  // If we're about to update a session's latest clock snapshot that hasn't been
3523
  // emitted into the trace yet, check whether the clocks have drifted enough to
3524
  // warrant overriding the current snapshot values. The older snapshot would be
3525
  // valid for a larger part of the currently buffered trace data because the
3526
  // clock sync protocol in trace processor uses the latest clock <= timestamp
3527
  // to translate times (see https://perfetto.dev/docs/concepts/clock-sync), so
3528
  // we try to keep it if we can.
3529
1.20k
  if (!snapshot_data->empty()) {
3530
300
    PERFETTO_DCHECK(snapshot_data->size() == new_snapshot_data.size());
3531
300
    PERFETTO_DCHECK((*snapshot_data)[0].clock_id ==
3532
300
                    protos::gen::BUILTIN_CLOCK_BOOTTIME);
3533
3534
300
    bool update_snapshot = false;
3535
300
    uint64_t old_boot_ns = (*snapshot_data)[0].timestamp;
3536
300
    uint64_t new_boot_ns = new_snapshot_data[0].timestamp;
3537
300
    int64_t boot_diff =
3538
300
        static_cast<int64_t>(new_boot_ns) - static_cast<int64_t>(old_boot_ns);
3539
3540
2.10k
    for (size_t i = 1; i < snapshot_data->size(); i++) {
3541
1.80k
      uint64_t old_ns = (*snapshot_data)[i].timestamp;
3542
1.80k
      uint64_t new_ns = new_snapshot_data[i].timestamp;
3543
3544
1.80k
      int64_t diff =
3545
1.80k
          static_cast<int64_t>(new_ns) - static_cast<int64_t>(old_ns);
3546
3547
      // Compare the boottime delta against the delta of this clock.
3548
1.80k
      if (std::abs(boot_diff - diff) >= kSignificantDriftNs) {
3549
0
        update_snapshot = true;
3550
0
        break;
3551
0
      }
3552
1.80k
    }
3553
300
    if (!update_snapshot)
3554
300
      return false;
3555
0
    snapshot_data->clear();
3556
0
  }
3557
3558
900
  *snapshot_data = std::move(new_snapshot_data);
3559
900
  return true;
3560
1.20k
}
3561
3562
void TracingServiceImpl::EmitClockSnapshot(
3563
    TracingSession* tracing_session,
3564
    TracingSession::ClockSnapshotData snapshot_data,
3565
600
    std::vector<TracePacket>* packets) {
3566
600
  PERFETTO_DCHECK(!tracing_session->config.builtin_data_sources()
3567
600
                       .disable_clock_snapshotting());
3568
3569
600
  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3570
600
  auto* snapshot = packet->set_clock_snapshot();
3571
3572
600
  protos::gen::BuiltinClock trace_clock =
3573
600
      tracing_session->config.builtin_data_sources().primary_trace_clock();
3574
600
  if (!trace_clock)
3575
600
    trace_clock = protos::gen::BUILTIN_CLOCK_BOOTTIME;
3576
600
  snapshot->set_primary_trace_clock(
3577
600
      static_cast<protos::pbzero::BuiltinClock>(trace_clock));
3578
3579
4.20k
  for (auto& clock_id_and_ts : snapshot_data) {
3580
4.20k
    auto* c = snapshot->add_clocks();
3581
4.20k
    c->set_clock_id(clock_id_and_ts.clock_id);
3582
4.20k
    c->set_timestamp(clock_id_and_ts.timestamp);
3583
4.20k
  }
3584
3585
600
  packet->set_trusted_uid(static_cast<int32_t>(uid_));
3586
600
  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3587
600
  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3588
600
}
3589
3590
300
void TracingServiceImpl::EmitSyncMarker(std::vector<TracePacket>* packets) {
3591
  // The sync marks are used to tokenize large traces efficiently.
3592
  // See description in trace_packet.proto.
3593
300
  if (sync_marker_packet_size_ == 0) {
3594
    // The marker ABI expects that the marker is written after the uid.
3595
    // Protozero guarantees that fields are written in the same order of the
3596
    // calls. The ResynchronizeTraceStreamUsingSyncMarker test verifies the ABI.
3597
300
    protozero::StaticBuffered<protos::pbzero::TracePacket> packet(
3598
300
        &sync_marker_packet_[0], sizeof(sync_marker_packet_));
3599
300
    packet->set_trusted_uid(static_cast<int32_t>(uid_));
3600
300
    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3601
3602
    // Keep this last.
3603
300
    packet->set_synchronization_marker(kSyncMarker, sizeof(kSyncMarker));
3604
300
    sync_marker_packet_size_ = packet.Finalize();
3605
300
  }
3606
300
  packets->emplace_back();
3607
300
  packets->back().AddSlice(&sync_marker_packet_[0], sync_marker_packet_size_);
3608
300
}
3609
3610
void TracingServiceImpl::EmitStats(TracingSession* tracing_session,
3611
300
                                   std::vector<TracePacket>* packets) {
3612
300
  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3613
300
  packet->set_trusted_uid(static_cast<int32_t>(uid_));
3614
300
  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3615
300
  GetTraceStats(tracing_session).Serialize(packet->set_trace_stats());
3616
300
  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3617
300
}
3618
3619
300
TraceStats TracingServiceImpl::GetTraceStats(TracingSession* tracing_session) {
3620
300
  TraceStats trace_stats;
3621
300
  trace_stats.set_producers_connected(static_cast<uint32_t>(producers_.size()));
3622
300
  trace_stats.set_producers_seen(last_producer_id_);
3623
300
  trace_stats.set_data_sources_registered(
3624
300
      static_cast<uint32_t>(data_sources_.size()));
3625
300
  trace_stats.set_data_sources_seen(last_data_source_instance_id_);
3626
300
  trace_stats.set_tracing_sessions(
3627
300
      static_cast<uint32_t>(tracing_sessions_.size()));
3628
300
  trace_stats.set_total_buffers(static_cast<uint32_t>(buffers_.size()));
3629
300
  trace_stats.set_chunks_discarded(chunks_discarded_);
3630
300
  trace_stats.set_patches_discarded(patches_discarded_);
3631
300
  trace_stats.set_invalid_packets(tracing_session->invalid_packets);
3632
300
  trace_stats.set_flushes_requested(tracing_session->flushes_requested);
3633
300
  trace_stats.set_flushes_succeeded(tracing_session->flushes_succeeded);
3634
300
  trace_stats.set_flushes_failed(tracing_session->flushes_failed);
3635
300
  trace_stats.set_final_flush_outcome(tracing_session->final_flush_outcome);
3636
3637
300
  if (tracing_session->trace_filter) {
3638
0
    auto* filt_stats = trace_stats.mutable_filter_stats();
3639
0
    filt_stats->set_input_packets(tracing_session->filter_input_packets);
3640
0
    filt_stats->set_input_bytes(tracing_session->filter_input_bytes);
3641
0
    filt_stats->set_output_bytes(tracing_session->filter_output_bytes);
3642
0
    filt_stats->set_errors(tracing_session->filter_errors);
3643
0
    filt_stats->set_time_taken_ns(tracing_session->filter_time_taken_ns);
3644
0
    for (uint64_t value : tracing_session->filter_bytes_discarded_per_buffer)
3645
0
      filt_stats->add_bytes_discarded_per_buffer(value);
3646
0
  }
3647
3648
300
  for (BufferID buf_id : tracing_session->buffers_index) {
3649
300
    TraceBuffer* buf = GetBufferByID(buf_id);
3650
300
    if (!buf) {
3651
0
      PERFETTO_DFATAL("Buffer not found.");
3652
0
      continue;
3653
0
    }
3654
300
    *trace_stats.add_buffer_stats() = buf->stats();
3655
300
  }  // for (buf in session).
3656
3657
300
  if (!tracing_session->config.builtin_data_sources()
3658
300
           .disable_chunk_usage_histograms()) {
3659
    // Emit chunk usage stats broken down by sequence ID (i.e. by trace-writer).
3660
    // Writer stats are updated by each TraceBuffer object at ReadBuffers time,
3661
    // and there can be >1 buffer per session. A trace writer never writes to
3662
    // more than one buffer (it's technically allowed but doesn't happen in the
3663
    // current impl of the tracing SDK).
3664
3665
300
    bool has_written_bucket_definition = false;
3666
300
    uint32_t buf_idx = static_cast<uint32_t>(-1);
3667
300
    for (const BufferID buf_id : tracing_session->buffers_index) {
3668
300
      ++buf_idx;
3669
300
      const TraceBuffer* buf = GetBufferByID(buf_id);
3670
300
      if (!buf)
3671
0
        continue;
3672
600
      for (auto it = buf->writer_stats().GetIterator(); it; ++it) {
3673
300
        const auto& hist = it.value().used_chunk_hist;
3674
300
        ProducerID p;
3675
300
        WriterID w;
3676
300
        GetProducerAndWriterID(it.key(), &p, &w);
3677
300
        if (!has_written_bucket_definition) {
3678
          // Serialize one-off the histogram bucket definition, which is the
3679
          // same for all entries in the map.
3680
300
          has_written_bucket_definition = true;
3681
          // The -1 in the loop below is to skip the implicit overflow bucket.
3682
3.30k
          for (size_t i = 0; i < hist.num_buckets() - 1; ++i) {
3683
3.00k
            trace_stats.add_chunk_payload_histogram_def(hist.GetBucketThres(i));
3684
3.00k
          }
3685
300
        }  // if(!has_written_bucket_definition)
3686
300
        auto* wri_stats = trace_stats.add_writer_stats();
3687
300
        wri_stats->set_sequence_id(
3688
300
            tracing_session->GetPacketSequenceID(kDefaultMachineID, p, w));
3689
300
        wri_stats->set_buffer(buf_idx);
3690
3.60k
        for (size_t i = 0; i < hist.num_buckets(); ++i) {
3691
3.30k
          wri_stats->add_chunk_payload_histogram_counts(hist.GetBucketCount(i));
3692
3.30k
          wri_stats->add_chunk_payload_histogram_sum(hist.GetBucketSum(i));
3693
3.30k
        }
3694
300
      }  // for each sequence (writer).
3695
300
    }    // for each buffer.
3696
300
  }      // if (!disable_chunk_usage_histograms)
3697
3698
300
  return trace_stats;
3699
300
}
3700
3701
void TracingServiceImpl::EmitUuid(TracingSession* tracing_session,
3702
300
                                  std::vector<TracePacket>* packets) {
3703
300
  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3704
300
  packet->set_trusted_uid(static_cast<int32_t>(uid_));
3705
300
  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3706
300
  auto* uuid = packet->set_trace_uuid();
3707
300
  uuid->set_lsb(tracing_session->trace_uuid.lsb());
3708
300
  uuid->set_msb(tracing_session->trace_uuid.msb());
3709
300
  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3710
300
}
3711
3712
void TracingServiceImpl::MaybeEmitTraceConfig(
3713
    TracingSession* tracing_session,
3714
300
    std::vector<TracePacket>* packets) {
3715
300
  if (tracing_session->did_emit_initial_packets)
3716
0
    return;
3717
300
  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3718
300
  packet->set_trusted_uid(static_cast<int32_t>(uid_));
3719
300
  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3720
300
  tracing_session->config.Serialize(packet->set_trace_config());
3721
300
  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3722
300
}
3723
3724
300
void TracingServiceImpl::EmitSystemInfo(std::vector<TracePacket>* packets) {
3725
300
  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3726
300
  auto* info = packet->set_system_info();
3727
300
  info->set_tracing_service_version(base::GetVersionString());
3728
3729
300
  std::optional<int32_t> tzoff = base::GetTimezoneOffsetMins();
3730
300
  if (tzoff.has_value())
3731
300
    info->set_timezone_off_mins(*tzoff);
3732
3733
300
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
3734
300
    !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
3735
300
  struct utsname uname_info;
3736
300
  if (uname(&uname_info) == 0) {
3737
300
    auto* utsname_info = info->set_utsname();
3738
300
    utsname_info->set_sysname(uname_info.sysname);
3739
300
    utsname_info->set_version(uname_info.version);
3740
300
    utsname_info->set_machine(uname_info.machine);
3741
300
    utsname_info->set_release(uname_info.release);
3742
300
  }
3743
300
  info->set_page_size(static_cast<uint32_t>(sysconf(_SC_PAGESIZE)));
3744
300
  info->set_num_cpus(static_cast<uint32_t>(sysconf(_SC_NPROCESSORS_CONF)));
3745
300
#endif  // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
3746
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
3747
  std::string fingerprint_value = base::GetAndroidProp("ro.build.fingerprint");
3748
  if (!fingerprint_value.empty()) {
3749
    info->set_android_build_fingerprint(fingerprint_value);
3750
  } else {
3751
    PERFETTO_ELOG("Unable to read ro.build.fingerprint");
3752
  }
3753
3754
  std::string device_manufacturer_value =
3755
      base::GetAndroidProp("ro.product.manufacturer");
3756
  if (!device_manufacturer_value.empty()) {
3757
    info->set_android_device_manufacturer(device_manufacturer_value);
3758
  } else {
3759
    PERFETTO_ELOG("Unable to read ro.product.manufacturer");
3760
  }
3761
3762
  std::string sdk_str_value = base::GetAndroidProp("ro.build.version.sdk");
3763
  std::optional<uint64_t> sdk_value = base::StringToUInt64(sdk_str_value);
3764
  if (sdk_value.has_value()) {
3765
    info->set_android_sdk_version(*sdk_value);
3766
  } else {
3767
    PERFETTO_ELOG("Unable to read ro.build.version.sdk");
3768
  }
3769
3770
  std::string soc_model_value = base::GetAndroidProp("ro.soc.model");
3771
  if (!soc_model_value.empty()) {
3772
    info->set_android_soc_model(soc_model_value);
3773
  } else {
3774
    PERFETTO_ELOG("Unable to read ro.soc.model");
3775
  }
3776
3777
  // guest_soc model is not always present
3778
  std::string guest_soc_model_value =
3779
      base::GetAndroidProp("ro.boot.guest_soc.model");
3780
  if (!guest_soc_model_value.empty()) {
3781
    info->set_android_guest_soc_model(guest_soc_model_value);
3782
  }
3783
3784
  std::string hw_rev_value = base::GetAndroidProp("ro.boot.hardware.revision");
3785
  if (!hw_rev_value.empty()) {
3786
    info->set_android_hardware_revision(hw_rev_value);
3787
  } else {
3788
    PERFETTO_ELOG("Unable to read ro.boot.hardware.revision");
3789
  }
3790
3791
  std::string hw_ufs_value = base::GetAndroidProp("ro.boot.hardware.ufs");
3792
  if (!hw_ufs_value.empty()) {
3793
    info->set_android_storage_model(hw_ufs_value);
3794
  } else {
3795
    PERFETTO_ELOG("Unable to read ro.boot.hardware.ufs");
3796
  }
3797
3798
  std::string hw_ddr_value = base::GetAndroidProp("ro.boot.hardware.ddr");
3799
  if (!hw_ddr_value.empty()) {
3800
    info->set_android_ram_model(hw_ddr_value);
3801
  } else {
3802
    PERFETTO_ELOG("Unable to read ro.boot.hardware.ddr");
3803
  }
3804
3805
#endif  // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
3806
300
  packet->set_trusted_uid(static_cast<int32_t>(uid_));
3807
300
  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3808
300
  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3809
300
}
3810
3811
void TracingServiceImpl::EmitLifecycleEvents(
3812
    TracingSession* tracing_session,
3813
600
    std::vector<TracePacket>* packets) {
3814
600
  using TimestampedPacket =
3815
600
      std::pair<int64_t /* ts */, std::vector<uint8_t> /* serialized packet */>;
3816
3817
600
  std::vector<TimestampedPacket> timestamped_packets;
3818
2.70k
  for (auto& event : tracing_session->lifecycle_events) {
3819
2.70k
    for (int64_t ts : event.timestamps) {
3820
900
      protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3821
900
      packet->set_timestamp(static_cast<uint64_t>(ts));
3822
900
      packet->set_trusted_uid(static_cast<int32_t>(uid_));
3823
900
      packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3824
3825
900
      auto* service_event = packet->set_service_event();
3826
900
      service_event->AppendVarInt(event.field_id, 1);
3827
900
      timestamped_packets.emplace_back(ts, packet.SerializeAsArray());
3828
900
    }
3829
2.70k
    event.timestamps.clear();
3830
2.70k
  }
3831
3832
600
  if (tracing_session->slow_start_event.has_value()) {
3833
0
    const TracingSession::ArbitraryLifecycleEvent& event =
3834
0
        *tracing_session->slow_start_event;
3835
0
    timestamped_packets.emplace_back(event.timestamp, std::move(event.data));
3836
0
  }
3837
600
  tracing_session->slow_start_event.reset();
3838
3839
600
  for (auto& event : tracing_session->last_flush_events) {
3840
0
    timestamped_packets.emplace_back(event.timestamp, std::move(event.data));
3841
0
  }
3842
600
  tracing_session->last_flush_events.clear();
3843
3844
600
  for (size_t i = 0; i < tracing_session->buffer_cloned_timestamps.size();
3845
600
       i++) {
3846
0
    protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3847
0
    int64_t ts = tracing_session->buffer_cloned_timestamps[i];
3848
0
    packet->set_timestamp(static_cast<uint64_t>(ts));
3849
0
    packet->set_trusted_uid(static_cast<int32_t>(uid_));
3850
0
    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3851
3852
0
    auto* service_event = packet->set_service_event();
3853
0
    service_event->set_buffer_cloned(static_cast<uint32_t>(i));
3854
3855
0
    timestamped_packets.emplace_back(ts, packet.SerializeAsArray());
3856
0
  }
3857
600
  tracing_session->buffer_cloned_timestamps.clear();
3858
3859
  // We sort by timestamp here to ensure that the "sequence" of lifecycle
3860
  // packets has monotonic timestamps like other sequences in the trace.
3861
  // Note that these events could still be out of order with respect to other
3862
  // events on the service packet sequence (e.g. trigger received packets).
3863
600
  std::sort(timestamped_packets.begin(), timestamped_packets.end(),
3864
600
            [](const TimestampedPacket& a, const TimestampedPacket& b) {
3865
300
              return a.first < b.first;
3866
300
            });
3867
3868
600
  for (auto& pair : timestamped_packets)
3869
900
    SerializeAndAppendPacket(packets, std::move(pair.second));
3870
600
}
3871
3872
void TracingServiceImpl::MaybeEmitRemoteClockSync(
3873
    TracingSession* tracing_session,
3874
0
    std::vector<TracePacket>* packets) {
3875
0
  if (tracing_session->did_emit_remote_clock_sync_)
3876
0
    return;
3877
3878
0
  std::unordered_set<MachineID> did_emit_machines;
3879
0
  for (const auto& id_and_relay_client : relay_clients_) {
3880
0
    const auto& relay_client = id_and_relay_client.second;
3881
0
    auto machine_id = relay_client->machine_id();
3882
0
    if (did_emit_machines.find(machine_id) != did_emit_machines.end())
3883
0
      continue;  // Already emitted for the machine (e.g. multiple clients).
3884
3885
0
    auto& sync_clock_snapshots = relay_client->synced_clocks();
3886
0
    if (sync_clock_snapshots.empty()) {
3887
0
      PERFETTO_DLOG("Clock not synchronized for machine ID = %" PRIu32,
3888
0
                    machine_id);
3889
0
      continue;
3890
0
    }
3891
3892
    // Don't emit twice for the same machine.
3893
0
    did_emit_machines.insert(machine_id);
3894
3895
0
    protozero::HeapBuffered<protos::pbzero::TracePacket> sync_packet;
3896
0
    sync_packet->set_machine_id(machine_id);
3897
0
    sync_packet->set_trusted_uid(static_cast<int32_t>(uid_));
3898
0
    auto* remote_clock_sync = sync_packet->set_remote_clock_sync();
3899
0
    for (const auto& sync_exchange : relay_client->synced_clocks()) {
3900
0
      auto* sync_exchange_msg = remote_clock_sync->add_synced_clocks();
3901
3902
0
      auto* client_snapshots = sync_exchange_msg->set_client_clocks();
3903
0
      for (const auto& client_clock : sync_exchange.client_clocks) {
3904
0
        auto* clock = client_snapshots->add_clocks();
3905
0
        clock->set_clock_id(client_clock.clock_id);
3906
0
        clock->set_timestamp(client_clock.timestamp);
3907
0
      }
3908
3909
0
      auto* host_snapshots = sync_exchange_msg->set_host_clocks();
3910
0
      for (const auto& host_clock : sync_exchange.host_clocks) {
3911
0
        auto* clock = host_snapshots->add_clocks();
3912
0
        clock->set_clock_id(host_clock.clock_id);
3913
0
        clock->set_timestamp(host_clock.timestamp);
3914
0
      }
3915
0
    }
3916
3917
0
    SerializeAndAppendPacket(packets, sync_packet.SerializeAsArray());
3918
0
  }
3919
3920
0
  tracing_session->did_emit_remote_clock_sync_ = true;
3921
0
}
3922
3923
void TracingServiceImpl::MaybeEmitCloneTrigger(
3924
    TracingSession* tracing_session,
3925
300
    std::vector<TracePacket>* packets) {
3926
300
  if (tracing_session->clone_trigger.has_value()) {
3927
0
    protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3928
0
    auto* trigger = packet->set_clone_snapshot_trigger();
3929
0
    const auto& info = tracing_session->clone_trigger.value();
3930
0
    trigger->set_trigger_name(info.trigger_name);
3931
0
    trigger->set_producer_name(info.producer_name);
3932
0
    trigger->set_trusted_producer_uid(static_cast<int32_t>(info.producer_uid));
3933
3934
0
    packet->set_timestamp(info.boot_time_ns);
3935
0
    packet->set_trusted_uid(static_cast<int32_t>(uid_));
3936
0
    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3937
0
    SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3938
0
  }
3939
300
}
3940
3941
void TracingServiceImpl::MaybeEmitReceivedTriggers(
3942
    TracingSession* tracing_session,
3943
300
    std::vector<TracePacket>* packets) {
3944
300
  PERFETTO_DCHECK(tracing_session->num_triggers_emitted_into_trace <=
3945
300
                  tracing_session->received_triggers.size());
3946
300
  for (size_t i = tracing_session->num_triggers_emitted_into_trace;
3947
300
       i < tracing_session->received_triggers.size(); ++i) {
3948
0
    const auto& info = tracing_session->received_triggers[i];
3949
0
    protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
3950
0
    auto* trigger = packet->set_trigger();
3951
0
    trigger->set_trigger_name(info.trigger_name);
3952
0
    trigger->set_producer_name(info.producer_name);
3953
0
    trigger->set_trusted_producer_uid(static_cast<int32_t>(info.producer_uid));
3954
3955
0
    packet->set_timestamp(info.boot_time_ns);
3956
0
    packet->set_trusted_uid(static_cast<int32_t>(uid_));
3957
0
    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
3958
0
    SerializeAndAppendPacket(packets, packet.SerializeAsArray());
3959
0
    ++tracing_session->num_triggers_emitted_into_trace;
3960
0
  }
3961
300
}
3962
3963
void TracingServiceImpl::MaybeLogUploadEvent(const TraceConfig& cfg,
3964
                                             const base::Uuid& uuid,
3965
                                             PerfettoStatsdAtom atom,
3966
1.20k
                                             const std::string& trigger_name) {
3967
1.20k
  if (!ShouldLogEvent(cfg))
3968
1.20k
    return;
3969
3970
1.20k
  PERFETTO_DCHECK(uuid);  // The UUID must be set at this point.
3971
0
  android_stats::MaybeLogUploadEvent(atom, uuid.lsb(), uuid.msb(),
3972
0
                                     trigger_name);
3973
0
}
3974
3975
void TracingServiceImpl::MaybeLogTriggerEvent(const TraceConfig& cfg,
3976
                                              PerfettoTriggerAtom atom,
3977
0
                                              const std::string& trigger_name) {
3978
0
  if (!ShouldLogEvent(cfg))
3979
0
    return;
3980
0
  android_stats::MaybeLogTriggerEvent(atom, trigger_name);
3981
0
}
3982
3983
size_t TracingServiceImpl::PurgeExpiredAndCountTriggerInWindow(
3984
    int64_t now_ns,
3985
0
    uint64_t trigger_name_hash) {
3986
0
  constexpr int64_t kOneDayInNs = 24ll * 60 * 60 * 1000 * 1000 * 1000;
3987
0
  PERFETTO_DCHECK(
3988
0
      std::is_sorted(trigger_history_.begin(), trigger_history_.end()));
3989
0
  size_t remove_count = 0;
3990
0
  size_t trigger_count = 0;
3991
0
  for (const TriggerHistory& h : trigger_history_) {
3992
0
    if (h.timestamp_ns < now_ns - kOneDayInNs) {
3993
0
      remove_count++;
3994
0
    } else if (h.name_hash == trigger_name_hash) {
3995
0
      trigger_count++;
3996
0
    }
3997
0
  }
3998
0
  trigger_history_.erase_front(remove_count);
3999
0
  return trigger_count;
4000
0
}
4001
4002
base::Status TracingServiceImpl::FlushAndCloneSession(
4003
    ConsumerEndpointImpl* consumer,
4004
0
    ConsumerEndpoint::CloneSessionArgs args) {
4005
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4006
0
  auto clone_target = FlushFlags::CloneTarget::kUnknown;
4007
4008
0
  TracingSession* session = nullptr;
4009
0
  if (args.for_bugreport) {
4010
0
    clone_target = FlushFlags::CloneTarget::kBugreport;
4011
0
  }
4012
0
  if (args.tsid != 0) {
4013
0
    if (args.tsid == kBugreportSessionId) {
4014
      // This branch is only here to support the legacy protocol where we could
4015
      // clone only a single session using the magic ID kBugreportSessionId.
4016
      // The newer perfetto --clone-all-for-bugreport first queries the existing
4017
      // sessions and then issues individual clone requests specifying real
4018
      // session IDs, setting args.{for_bugreport,skip_trace_filter}=true.
4019
0
      PERFETTO_LOG("Looking for sessions for bugreport");
4020
0
      session = FindTracingSessionWithMaxBugreportScore();
4021
0
      if (!session) {
4022
0
        return base::ErrStatus(
4023
0
            "No tracing sessions eligible for bugreport found");
4024
0
      }
4025
0
      args.tsid = session->id;
4026
0
      clone_target = FlushFlags::CloneTarget::kBugreport;
4027
0
      args.skip_trace_filter = true;
4028
0
    } else {
4029
0
      session = GetTracingSession(args.tsid);
4030
0
    }
4031
0
  } else if (!args.unique_session_name.empty()) {
4032
0
    session = GetTracingSessionByUniqueName(args.unique_session_name);
4033
0
  }
4034
4035
0
  if (!session) {
4036
0
    return base::ErrStatus("Tracing session not found");
4037
0
  }
4038
4039
  // Skip the UID check for sessions marked with a bugreport_score > 0.
4040
  // Those sessions, by design, can be stolen by any other consumer for the
4041
  // sake of creating snapshots for bugreports.
4042
0
  if (!session->IsCloneAllowed(consumer->uid_)) {
4043
0
    return PERFETTO_SVC_ERR("Not allowed to clone a session from another UID");
4044
0
  }
4045
4046
  // If any of the buffers are marked as clear_before_clone, reset them before
4047
  // issuing the Flush(kCloneReason).
4048
0
  size_t buf_idx = 0;
4049
0
  for (BufferID src_buf_id : session->buffers_index) {
4050
0
    if (!session->config.buffers()[buf_idx++].clear_before_clone())
4051
0
      continue;
4052
0
    auto buf_iter = buffers_.find(src_buf_id);
4053
0
    PERFETTO_CHECK(buf_iter != buffers_.end());
4054
0
    std::unique_ptr<TraceBuffer>& buf = buf_iter->second;
4055
4056
    // No need to reset the buffer if nothing has been written into it yet.
4057
    // This is the canonical case if producers behive nicely and don't timeout
4058
    // the handling of writes during the flush.
4059
    // This check avoids a useless re-mmap upon every Clone() if the buffer is
4060
    // already empty (when used in combination with `transfer_on_clone`).
4061
0
    if (!buf->has_data())
4062
0
      continue;
4063
4064
    // Some leftover data was left in the buffer. Recreate it to empty it.
4065
0
    const auto buf_policy = buf->overwrite_policy();
4066
0
    const auto buf_size = buf->size();
4067
0
    std::unique_ptr<TraceBuffer> old_buf = std::move(buf);
4068
0
    buf = TraceBuffer::Create(buf_size, buf_policy);
4069
0
    if (!buf) {
4070
      // This is extremely rare but could happen on 32-bit. If the new buffer
4071
      // allocation failed, put back the buffer where it was and fail the clone.
4072
      // We cannot leave the original tracing session buffer-less as it would
4073
      // cause crashes when data sources commit new data.
4074
0
      buf = std::move(old_buf);
4075
0
      return base::ErrStatus(
4076
0
          "Buffer allocation failed while attempting to clone");
4077
0
    }
4078
0
  }
4079
4080
0
  auto weak_consumer = consumer->GetWeakPtr();
4081
4082
0
  const PendingCloneID clone_id = session->last_pending_clone_id_++;
4083
4084
0
  auto& clone_op = session->pending_clones[clone_id];
4085
0
  clone_op.pending_flush_cnt = 0;
4086
  // Pre-initialize these vectors just as an optimization to avoid reallocations
4087
  // in DoCloneBuffers().
4088
0
  clone_op.buffers.reserve(session->buffers_index.size());
4089
0
  clone_op.buffer_cloned_timestamps.reserve(session->buffers_index.size());
4090
0
  clone_op.weak_consumer = weak_consumer;
4091
0
  clone_op.skip_trace_filter = args.skip_trace_filter;
4092
0
  if (!args.clone_trigger_name.empty()) {
4093
0
    clone_op.clone_trigger = {args.clone_trigger_boot_time_ns,
4094
0
                              args.clone_trigger_name,
4095
0
                              args.clone_trigger_producer_name,
4096
0
                              args.clone_trigger_trusted_producer_uid};
4097
0
  }
4098
4099
  // Issue separate flush requests for separate buffer groups. The buffer marked
4100
  // as transfer_on_clone will be flushed and cloned separately: even if they're
4101
  // slower (like in the case of Winscope tracing), they will not delay the
4102
  // snapshot of the other buffers.
4103
  //
4104
  // In the future we might want to split the buffer into more groups and maybe
4105
  // allow this to be configurable.
4106
0
  std::array<std::set<BufferID>, 2> bufs_groups;
4107
0
  for (size_t i = 0; i < session->buffers_index.size(); i++) {
4108
0
    if (session->config.buffers()[i].transfer_on_clone()) {
4109
0
      bufs_groups[0].insert(session->buffers_index[i]);
4110
0
    } else {
4111
0
      bufs_groups[1].insert(session->buffers_index[i]);
4112
0
    }
4113
0
  }
4114
4115
0
  SnapshotLifecycleEvent(
4116
0
      session, protos::pbzero::TracingServiceEvent::kFlushStartedFieldNumber,
4117
0
      false /* snapshot_clocks */);
4118
0
  clone_op.pending_flush_cnt = bufs_groups.size();
4119
0
  clone_op.clone_started_timestamp_ns = clock_->GetBootTimeNs().count();
4120
0
  for (const std::set<BufferID>& buf_group : bufs_groups) {
4121
0
    FlushDataSourceInstances(
4122
0
        session, 0,
4123
0
        GetFlushableDataSourceInstancesForBuffers(session, buf_group),
4124
0
        [tsid = session->id, clone_id, buf_group, this](bool final_flush) {
4125
0
          OnFlushDoneForClone(tsid, clone_id, buf_group, final_flush);
4126
0
        },
4127
0
        FlushFlags(FlushFlags::Initiator::kTraced,
4128
0
                   FlushFlags::Reason::kTraceClone, clone_target));
4129
0
  }
4130
4131
0
  return base::OkStatus();
4132
0
}
4133
4134
std::map<ProducerID, std::vector<DataSourceInstanceID>>
4135
TracingServiceImpl::GetFlushableDataSourceInstancesForBuffers(
4136
    TracingSession* session,
4137
0
    const std::set<BufferID>& bufs) {
4138
0
  std::map<ProducerID, std::vector<DataSourceInstanceID>> data_source_instances;
4139
4140
0
  for (const auto& [producer_id, ds_inst] : session->data_source_instances) {
4141
    // TODO(ddiproietto): Consider if we should skip instances if ds_inst.state
4142
    // != DataSourceInstance::STARTED
4143
0
    if (ds_inst.no_flush) {
4144
0
      continue;
4145
0
    }
4146
0
    if (!bufs.count(static_cast<BufferID>(ds_inst.config.target_buffer()))) {
4147
0
      continue;
4148
0
    }
4149
0
    data_source_instances[producer_id].push_back(ds_inst.instance_id);
4150
0
  }
4151
4152
0
  return data_source_instances;
4153
0
}
4154
4155
void TracingServiceImpl::OnFlushDoneForClone(TracingSessionID tsid,
4156
                                             PendingCloneID clone_id,
4157
                                             const std::set<BufferID>& buf_ids,
4158
0
                                             bool final_flush_outcome) {
4159
0
  TracingSession* src = GetTracingSession(tsid);
4160
  // The session might be gone by the time we try to clone it.
4161
0
  if (!src) {
4162
0
    return;
4163
0
  }
4164
4165
0
  auto it = src->pending_clones.find(clone_id);
4166
0
  if (it == src->pending_clones.end()) {
4167
0
    return;
4168
0
  }
4169
0
  auto& clone_op = it->second;
4170
4171
0
  if (final_flush_outcome == false) {
4172
0
    clone_op.flush_failed = true;
4173
0
  }
4174
4175
0
  base::Status result;
4176
0
  base::Uuid uuid;
4177
4178
  // First clone the flushed TraceBuffer(s). This can fail because of ENOMEM. If
4179
  // it happens bail out early before creating any session.
4180
0
  if (!DoCloneBuffers(*src, buf_ids, &clone_op)) {
4181
0
    result = PERFETTO_SVC_ERR("Buffer allocation failed");
4182
0
  }
4183
4184
0
  if (result.ok()) {
4185
0
    UpdateMemoryGuardrail();
4186
4187
0
    if (--clone_op.pending_flush_cnt != 0) {
4188
      // Wait for more pending flushes.
4189
0
      return;
4190
0
    }
4191
4192
0
    PERFETTO_LOG("FlushAndCloneSession(%" PRIu64 ") started, success=%d", tsid,
4193
0
                 final_flush_outcome);
4194
4195
0
    if (clone_op.weak_consumer) {
4196
0
      result = FinishCloneSession(
4197
0
          &*clone_op.weak_consumer, tsid, std::move(clone_op.buffers),
4198
0
          std::move(clone_op.buffer_cloned_timestamps),
4199
0
          clone_op.skip_trace_filter, !clone_op.flush_failed,
4200
0
          clone_op.clone_trigger, &uuid, clone_op.clone_started_timestamp_ns);
4201
0
    }
4202
0
  }  // if (result.ok())
4203
4204
0
  if (clone_op.weak_consumer) {
4205
0
    clone_op.weak_consumer->consumer_->OnSessionCloned(
4206
0
        {result.ok(), result.message(), uuid});
4207
0
  }
4208
4209
0
  src->pending_clones.erase(it);
4210
0
  UpdateMemoryGuardrail();
4211
0
}
4212
4213
bool TracingServiceImpl::DoCloneBuffers(const TracingSession& src,
4214
                                        const std::set<BufferID>& buf_ids,
4215
0
                                        PendingClone* clone_op) {
4216
0
  PERFETTO_DCHECK(src.num_buffers() == src.config.buffers().size());
4217
0
  clone_op->buffers.resize(src.buffers_index.size());
4218
0
  clone_op->buffer_cloned_timestamps.resize(src.buffers_index.size());
4219
4220
0
  int64_t now = clock_->GetBootTimeNs().count();
4221
4222
0
  for (size_t buf_idx = 0; buf_idx < src.buffers_index.size(); buf_idx++) {
4223
0
    BufferID src_buf_id = src.buffers_index[buf_idx];
4224
0
    if (buf_ids.count(src_buf_id) == 0)
4225
0
      continue;
4226
0
    auto buf_iter = buffers_.find(src_buf_id);
4227
0
    PERFETTO_CHECK(buf_iter != buffers_.end());
4228
0
    std::unique_ptr<TraceBuffer>& src_buf = buf_iter->second;
4229
0
    std::unique_ptr<TraceBuffer> new_buf;
4230
0
    if (src.config.buffers()[buf_idx].transfer_on_clone()) {
4231
0
      const auto buf_policy = src_buf->overwrite_policy();
4232
0
      const auto buf_size = src_buf->size();
4233
0
      new_buf = std::move(src_buf);
4234
0
      src_buf = TraceBuffer::Create(buf_size, buf_policy);
4235
0
      if (!src_buf) {
4236
        // If the allocation fails put the buffer back and let the code below
4237
        // handle the failure gracefully.
4238
0
        src_buf = std::move(new_buf);
4239
0
      }
4240
0
    } else {
4241
0
      new_buf = src_buf->CloneReadOnly();
4242
0
    }
4243
0
    if (!new_buf.get()) {
4244
0
      return false;
4245
0
    }
4246
0
    clone_op->buffers[buf_idx] = std::move(new_buf);
4247
0
    clone_op->buffer_cloned_timestamps[buf_idx] = now;
4248
0
  }
4249
0
  return true;
4250
0
}
4251
4252
base::Status TracingServiceImpl::FinishCloneSession(
4253
    ConsumerEndpointImpl* consumer,
4254
    TracingSessionID src_tsid,
4255
    std::vector<std::unique_ptr<TraceBuffer>> buf_snaps,
4256
    std::vector<int64_t> buf_cloned_timestamps,
4257
    bool skip_trace_filter,
4258
    bool final_flush_outcome,
4259
    std::optional<TriggerInfo> clone_trigger,
4260
    base::Uuid* new_uuid,
4261
0
    int64_t clone_started_timestamp_ns) {
4262
0
  PERFETTO_DLOG("CloneSession(%" PRIu64
4263
0
                ", skip_trace_filter=%d) started, consumer uid: %d",
4264
0
                src_tsid, skip_trace_filter, static_cast<int>(consumer->uid_));
4265
4266
0
  TracingSession* src = GetTracingSession(src_tsid);
4267
4268
  // The session might be gone by the time we try to clone it.
4269
0
  if (!src)
4270
0
    return PERFETTO_SVC_ERR("session not found");
4271
4272
0
  if (consumer->tracing_session_id_) {
4273
0
    return PERFETTO_SVC_ERR(
4274
0
        "The consumer is already attached to another tracing session");
4275
0
  }
4276
4277
0
  std::vector<BufferID> buf_ids =
4278
0
      buffer_ids_.AllocateMultiple(buf_snaps.size());
4279
0
  if (buf_ids.size() != buf_snaps.size()) {
4280
0
    return PERFETTO_SVC_ERR("Buffer id allocation failed");
4281
0
  }
4282
4283
0
  PERFETTO_CHECK(std::none_of(
4284
0
      buf_snaps.begin(), buf_snaps.end(),
4285
0
      [](const std::unique_ptr<TraceBuffer>& buf) { return buf == nullptr; }));
4286
4287
0
  const TracingSessionID tsid = ++last_tracing_session_id_;
4288
0
  TracingSession* cloned_session =
4289
0
      &tracing_sessions_
4290
0
           .emplace(std::piecewise_construct, std::forward_as_tuple(tsid),
4291
0
                    std::forward_as_tuple(tsid, consumer, src->config,
4292
0
                                          weak_runner_.task_runner()))
4293
0
           .first->second;
4294
4295
  // Generate a new UUID for the cloned session, but preserve the LSB. In some
4296
  // contexts the LSB is used to tie the trace back to the statsd subscription
4297
  // that triggered it. See the corresponding code in perfetto_cmd.cc which
4298
  // reads at triggering_subscription_id().
4299
0
  const int64_t orig_uuid_lsb = src->trace_uuid.lsb();
4300
0
  cloned_session->state = TracingSession::CLONED_READ_ONLY;
4301
0
  cloned_session->trace_uuid = base::Uuidv4();
4302
0
  cloned_session->trace_uuid.set_lsb(orig_uuid_lsb);
4303
0
  *new_uuid = cloned_session->trace_uuid;
4304
4305
0
  for (size_t i = 0; i < buf_snaps.size(); i++) {
4306
0
    BufferID buf_global_id = buf_ids[i];
4307
0
    std::unique_ptr<TraceBuffer>& buf = buf_snaps[i];
4308
    // This is only needed for transfer_on_clone. Other buffers are already
4309
    // marked as read-only by CloneReadOnly(). We cannot do this early because
4310
    // in case of an allocation failure we will put std::move() the original
4311
    // buffer back in its place and in that case should not be made read-only.
4312
0
    buf->set_read_only();
4313
0
    buffers_.emplace(buf_global_id, std::move(buf));
4314
0
    cloned_session->buffers_index.emplace_back(buf_global_id);
4315
0
  }
4316
0
  UpdateMemoryGuardrail();
4317
4318
  // Copy over relevant state that we want to persist in the cloned session.
4319
  // Mostly stats and metadata that is emitted in the trace file by the service.
4320
  // Also clear the received trigger list in the main tracing session. A
4321
  // CLONE_SNAPSHOT session can go in ring buffer mode for several hours and get
4322
  // snapshotted several times. This causes two issues with `received_triggers`:
4323
  // 1. Adding noise in the cloned trace emitting triggers that happened too
4324
  //    far back (see b/290799105).
4325
  // 2. Bloating memory (see b/290798988).
4326
0
  cloned_session->should_emit_stats = true;
4327
0
  cloned_session->clone_trigger = clone_trigger;
4328
0
  cloned_session->received_triggers = std::move(src->received_triggers);
4329
0
  src->received_triggers.clear();
4330
0
  src->num_triggers_emitted_into_trace = 0;
4331
0
  cloned_session->lifecycle_events =
4332
0
      std::vector<TracingSession::LifecycleEvent>(src->lifecycle_events);
4333
0
  cloned_session->slow_start_event = src->slow_start_event;
4334
0
  cloned_session->last_flush_events = src->last_flush_events;
4335
0
  cloned_session->initial_clock_snapshot = src->initial_clock_snapshot;
4336
0
  cloned_session->clock_snapshot_ring_buffer = src->clock_snapshot_ring_buffer;
4337
0
  cloned_session->invalid_packets = src->invalid_packets;
4338
0
  cloned_session->flushes_requested = src->flushes_requested;
4339
0
  cloned_session->flushes_succeeded = src->flushes_succeeded;
4340
0
  cloned_session->flushes_failed = src->flushes_failed;
4341
0
  cloned_session->compress_deflate = src->compress_deflate;
4342
0
  if (src->trace_filter && !skip_trace_filter) {
4343
    // Copy the trace filter, unless it's a clone-for-bugreport (b/317065412).
4344
0
    cloned_session->trace_filter.reset(
4345
0
        new protozero::MessageFilter(src->trace_filter->config()));
4346
0
  }
4347
4348
0
  cloned_session->buffer_cloned_timestamps = std::move(buf_cloned_timestamps);
4349
4350
0
  SetSingleLifecycleEvent(
4351
0
      cloned_session,
4352
0
      protos::pbzero::TracingServiceEvent::kCloneStartedFieldNumber,
4353
0
      clone_started_timestamp_ns);
4354
4355
0
  SnapshotLifecycleEvent(
4356
0
      cloned_session,
4357
0
      protos::pbzero::TracingServiceEvent::kTracingDisabledFieldNumber,
4358
0
      true /* snapshot_clocks */);
4359
4360
0
  PERFETTO_DLOG("Consumer (uid:%d) cloned tracing session %" PRIu64
4361
0
                " -> %" PRIu64,
4362
0
                static_cast<int>(consumer->uid_), src_tsid, tsid);
4363
4364
0
  consumer->tracing_session_id_ = tsid;
4365
0
  cloned_session->final_flush_outcome = final_flush_outcome
4366
0
                                            ? TraceStats::FINAL_FLUSH_SUCCEEDED
4367
0
                                            : TraceStats::FINAL_FLUSH_FAILED;
4368
0
  return base::OkStatus();
4369
0
}
4370
4371
0
bool TracingServiceImpl::TracingSession::IsCloneAllowed(uid_t clone_uid) const {
4372
0
  if (clone_uid == 0)
4373
0
    return true;  // Root is always allowed to clone everything.
4374
0
  if (clone_uid == this->consumer_uid)
4375
0
    return true;  // Allow cloning if the uids match.
4376
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
4377
  // On Android allow shell to clone sessions marked as exported for bugreport.
4378
  // Dumpstate (invoked by adb bugreport) invokes commands as shell.
4379
  if (clone_uid == AID_SHELL && this->config.bugreport_score() > 0)
4380
    return true;
4381
#endif
4382
0
  return false;
4383
0
}
4384
4385
////////////////////////////////////////////////////////////////////////////////
4386
// TracingServiceImpl::ConsumerEndpointImpl implementation
4387
////////////////////////////////////////////////////////////////////////////////
4388
4389
TracingServiceImpl::ConsumerEndpointImpl::ConsumerEndpointImpl(
4390
    TracingServiceImpl* service,
4391
    base::TaskRunner* task_runner,
4392
    Consumer* consumer,
4393
    uid_t uid)
4394
300
    : task_runner_(task_runner),
4395
300
      service_(service),
4396
300
      consumer_(consumer),
4397
300
      uid_(uid),
4398
300
      weak_ptr_factory_(this) {}
4399
4400
300
TracingServiceImpl::ConsumerEndpointImpl::~ConsumerEndpointImpl() {
4401
300
  service_->DisconnectConsumer(this);
4402
300
  consumer_->OnDisconnect();
4403
300
}
4404
4405
void TracingServiceImpl::ConsumerEndpointImpl::NotifyOnTracingDisabled(
4406
300
    const std::string& error) {
4407
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4408
300
  task_runner_->PostTask([weak_this = weak_ptr_factory_.GetWeakPtr(),
4409
300
                          error /* deliberate copy */] {
4410
300
    if (weak_this)
4411
0
      weak_this->consumer_->OnTracingDisabled(error);
4412
300
  });
4413
300
}
4414
4415
void TracingServiceImpl::ConsumerEndpointImpl::EnableTracing(
4416
    const TraceConfig& cfg,
4417
300
    base::ScopedFile fd) {
4418
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4419
300
  auto status = service_->EnableTracing(this, cfg, std::move(fd));
4420
300
  if (!status.ok())
4421
0
    NotifyOnTracingDisabled(status.message());
4422
300
}
4423
4424
void TracingServiceImpl::ConsumerEndpointImpl::ChangeTraceConfig(
4425
0
    const TraceConfig& cfg) {
4426
0
  if (!tracing_session_id_) {
4427
0
    PERFETTO_LOG(
4428
0
        "Consumer called ChangeTraceConfig() but tracing was "
4429
0
        "not active");
4430
0
    return;
4431
0
  }
4432
0
  service_->ChangeTraceConfig(this, cfg);
4433
0
}
4434
4435
0
void TracingServiceImpl::ConsumerEndpointImpl::StartTracing() {
4436
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4437
0
  if (!tracing_session_id_) {
4438
0
    PERFETTO_LOG("Consumer called StartTracing() but tracing was not active");
4439
0
    return;
4440
0
  }
4441
0
  service_->StartTracing(tracing_session_id_);
4442
0
}
4443
4444
0
void TracingServiceImpl::ConsumerEndpointImpl::DisableTracing() {
4445
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4446
0
  if (!tracing_session_id_) {
4447
0
    PERFETTO_LOG("Consumer called DisableTracing() but tracing was not active");
4448
0
    return;
4449
0
  }
4450
0
  service_->DisableTracing(tracing_session_id_);
4451
0
}
4452
4453
300
void TracingServiceImpl::ConsumerEndpointImpl::ReadBuffers() {
4454
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4455
300
  if (!tracing_session_id_) {
4456
0
    PERFETTO_LOG("Consumer called ReadBuffers() but tracing was not active");
4457
0
    consumer_->OnTraceData({}, /* has_more = */ false);
4458
0
    return;
4459
0
  }
4460
300
  if (!service_->ReadBuffersIntoConsumer(tracing_session_id_, this)) {
4461
0
    consumer_->OnTraceData({}, /* has_more = */ false);
4462
0
  }
4463
300
}
4464
4465
0
void TracingServiceImpl::ConsumerEndpointImpl::FreeBuffers() {
4466
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4467
0
  if (!tracing_session_id_) {
4468
0
    PERFETTO_LOG("Consumer called FreeBuffers() but tracing was not active");
4469
0
    return;
4470
0
  }
4471
0
  service_->FreeBuffers(tracing_session_id_);
4472
0
  tracing_session_id_ = 0;
4473
0
}
4474
4475
void TracingServiceImpl::ConsumerEndpointImpl::Flush(uint32_t timeout_ms,
4476
                                                     FlushCallback callback,
4477
0
                                                     FlushFlags flush_flags) {
4478
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4479
0
  if (!tracing_session_id_) {
4480
0
    PERFETTO_LOG("Consumer called Flush() but tracing was not active");
4481
0
    return;
4482
0
  }
4483
0
  service_->Flush(tracing_session_id_, timeout_ms, callback, flush_flags);
4484
0
}
4485
4486
0
void TracingServiceImpl::ConsumerEndpointImpl::Detach(const std::string& key) {
4487
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4488
0
  bool success = service_->DetachConsumer(this, key);
4489
0
  auto weak_this = weak_ptr_factory_.GetWeakPtr();
4490
0
  task_runner_->PostTask([weak_this = std::move(weak_this), success] {
4491
0
    if (weak_this)
4492
0
      weak_this->consumer_->OnDetach(success);
4493
0
  });
4494
0
}
4495
4496
0
void TracingServiceImpl::ConsumerEndpointImpl::Attach(const std::string& key) {
4497
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4498
0
  bool success = service_->AttachConsumer(this, key);
4499
0
  task_runner_->PostTask([weak_this = weak_ptr_factory_.GetWeakPtr(), success] {
4500
0
    if (!weak_this)
4501
0
      return;
4502
0
    Consumer* consumer = weak_this->consumer_;
4503
0
    TracingSession* session =
4504
0
        weak_this->service_->GetTracingSession(weak_this->tracing_session_id_);
4505
0
    if (!session) {
4506
0
      consumer->OnAttach(false, TraceConfig());
4507
0
      return;
4508
0
    }
4509
0
    consumer->OnAttach(success, session->config);
4510
0
  });
4511
0
}
4512
4513
0
void TracingServiceImpl::ConsumerEndpointImpl::GetTraceStats() {
4514
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4515
0
  bool success = false;
4516
0
  TraceStats stats;
4517
0
  TracingSession* session = service_->GetTracingSession(tracing_session_id_);
4518
0
  if (session) {
4519
0
    success = true;
4520
0
    stats = service_->GetTraceStats(session);
4521
0
  }
4522
0
  auto weak_this = weak_ptr_factory_.GetWeakPtr();
4523
0
  task_runner_->PostTask(
4524
0
      [weak_this = std::move(weak_this), success, stats = std::move(stats)] {
4525
0
        if (weak_this)
4526
0
          weak_this->consumer_->OnTraceStats(success, stats);
4527
0
      });
4528
0
}
4529
4530
void TracingServiceImpl::ConsumerEndpointImpl::ObserveEvents(
4531
300
    uint32_t events_mask) {
4532
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4533
300
  observable_events_mask_ = events_mask;
4534
300
  TracingSession* session = service_->GetTracingSession(tracing_session_id_);
4535
300
  if (!session)
4536
300
    return;
4537
4538
0
  if (observable_events_mask_ & ObservableEvents::TYPE_DATA_SOURCES_INSTANCES) {
4539
    // Issue initial states.
4540
0
    for (const auto& kv : session->data_source_instances) {
4541
0
      ProducerEndpointImpl* producer = service_->GetProducer(kv.first);
4542
0
      PERFETTO_DCHECK(producer);
4543
0
      OnDataSourceInstanceStateChange(*producer, kv.second);
4544
0
    }
4545
0
  }
4546
4547
  // If the ObserveEvents() call happens after data sources have acked already
4548
  // notify immediately.
4549
0
  if (observable_events_mask_ &
4550
0
      ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED) {
4551
0
    service_->MaybeNotifyAllDataSourcesStarted(session);
4552
0
  }
4553
0
}
4554
4555
void TracingServiceImpl::ConsumerEndpointImpl::OnDataSourceInstanceStateChange(
4556
    const ProducerEndpointImpl& producer,
4557
900
    const DataSourceInstance& instance) {
4558
900
  if (!(observable_events_mask_ &
4559
900
        ObservableEvents::TYPE_DATA_SOURCES_INSTANCES)) {
4560
900
    return;
4561
900
  }
4562
4563
0
  if (instance.state != DataSourceInstance::CONFIGURED &&
4564
0
      instance.state != DataSourceInstance::STARTED &&
4565
0
      instance.state != DataSourceInstance::STOPPED) {
4566
0
    return;
4567
0
  }
4568
4569
0
  auto* observable_events = AddObservableEvents();
4570
0
  auto* change = observable_events->add_instance_state_changes();
4571
0
  change->set_producer_name(producer.name_);
4572
0
  change->set_data_source_name(instance.data_source_name);
4573
0
  if (instance.state == DataSourceInstance::STARTED) {
4574
0
    change->set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED);
4575
0
  } else {
4576
0
    change->set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED);
4577
0
  }
4578
0
}
4579
4580
300
void TracingServiceImpl::ConsumerEndpointImpl::OnAllDataSourcesStarted() {
4581
300
  if (!(observable_events_mask_ &
4582
300
        ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED)) {
4583
0
    return;
4584
0
  }
4585
300
  auto* observable_events = AddObservableEvents();
4586
300
  observable_events->set_all_data_sources_started(true);
4587
300
}
4588
4589
void TracingServiceImpl::ConsumerEndpointImpl::NotifyCloneSnapshotTrigger(
4590
0
    const TriggerInfo& trigger) {
4591
0
  if (!(observable_events_mask_ & ObservableEvents::TYPE_CLONE_TRIGGER_HIT)) {
4592
0
    return;
4593
0
  }
4594
0
  auto* observable_events = AddObservableEvents();
4595
0
  auto* clone_trig = observable_events->mutable_clone_trigger_hit();
4596
0
  clone_trig->set_tracing_session_id(static_cast<int64_t>(tracing_session_id_));
4597
0
  clone_trig->set_trigger_name(trigger.trigger_name);
4598
0
  clone_trig->set_producer_name(trigger.producer_name);
4599
0
  clone_trig->set_producer_uid(static_cast<uint32_t>(trigger.producer_uid));
4600
0
  clone_trig->set_boot_time_ns(trigger.boot_time_ns);
4601
0
}
4602
4603
ObservableEvents*
4604
300
TracingServiceImpl::ConsumerEndpointImpl::AddObservableEvents() {
4605
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4606
300
  if (!observable_events_) {
4607
300
    observable_events_.reset(new ObservableEvents());
4608
300
    task_runner_->PostTask([weak_this = weak_ptr_factory_.GetWeakPtr()] {
4609
300
      if (!weak_this)
4610
0
        return;
4611
4612
      // Move into a temporary to allow reentrancy in OnObservableEvents.
4613
300
      auto observable_events = std::move(weak_this->observable_events_);
4614
300
      weak_this->consumer_->OnObservableEvents(*observable_events);
4615
300
    });
4616
300
  }
4617
300
  return observable_events_.get();
4618
300
}
4619
4620
void TracingServiceImpl::ConsumerEndpointImpl::QueryServiceState(
4621
    QueryServiceStateArgs args,
4622
0
    QueryServiceStateCallback callback) {
4623
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4624
0
  TracingServiceState svc_state;
4625
4626
0
  const auto& sessions = service_->tracing_sessions_;
4627
0
  svc_state.set_tracing_service_version(base::GetVersionString());
4628
0
  svc_state.set_num_sessions(static_cast<int>(sessions.size()));
4629
4630
0
  int num_started = 0;
4631
0
  for (const auto& kv : sessions)
4632
0
    num_started += kv.second.state == TracingSession::State::STARTED ? 1 : 0;
4633
0
  svc_state.set_num_sessions_started(num_started);
4634
4635
0
  for (const auto& kv : service_->producers_) {
4636
0
    if (args.sessions_only)
4637
0
      break;
4638
0
    auto* producer = svc_state.add_producers();
4639
0
    producer->set_id(static_cast<int>(kv.first));
4640
0
    producer->set_name(kv.second->name_);
4641
0
    producer->set_sdk_version(kv.second->sdk_version_);
4642
0
    producer->set_uid(static_cast<int32_t>(kv.second->uid()));
4643
0
    producer->set_pid(static_cast<int32_t>(kv.second->pid()));
4644
0
    producer->set_frozen(kv.second->IsAndroidProcessFrozen());
4645
0
  }
4646
4647
0
  for (const auto& kv : service_->data_sources_) {
4648
0
    if (args.sessions_only)
4649
0
      break;
4650
0
    const auto& registered_data_source = kv.second;
4651
0
    auto* data_source = svc_state.add_data_sources();
4652
0
    *data_source->mutable_ds_descriptor() = registered_data_source.descriptor;
4653
0
    data_source->set_producer_id(
4654
0
        static_cast<int>(registered_data_source.producer_id));
4655
0
  }
4656
4657
0
  svc_state.set_supports_tracing_sessions(true);
4658
0
  for (const auto& kv : service_->tracing_sessions_) {
4659
0
    const TracingSession& s = kv.second;
4660
0
    if (!s.IsCloneAllowed(uid_))
4661
0
      continue;
4662
0
    auto* session = svc_state.add_tracing_sessions();
4663
0
    session->set_id(s.id);
4664
0
    session->set_consumer_uid(static_cast<int>(s.consumer_uid));
4665
0
    session->set_duration_ms(s.config.duration_ms());
4666
0
    session->set_num_data_sources(
4667
0
        static_cast<uint32_t>(s.data_source_instances.size()));
4668
0
    session->set_unique_session_name(s.config.unique_session_name());
4669
0
    if (s.config.has_bugreport_score())
4670
0
      session->set_bugreport_score(s.config.bugreport_score());
4671
0
    if (s.config.has_bugreport_filename())
4672
0
      session->set_bugreport_filename(s.config.bugreport_filename());
4673
0
    for (const auto& snap_kv : s.initial_clock_snapshot) {
4674
0
      if (snap_kv.clock_id == protos::pbzero::BUILTIN_CLOCK_REALTIME)
4675
0
        session->set_start_realtime_ns(static_cast<int64_t>(snap_kv.timestamp));
4676
0
    }
4677
0
    for (const auto& buf : s.config.buffers())
4678
0
      session->add_buffer_size_kb(buf.size_kb());
4679
4680
0
    switch (s.state) {
4681
0
      case TracingSession::State::DISABLED:
4682
0
        session->set_state("DISABLED");
4683
0
        break;
4684
0
      case TracingSession::State::CONFIGURED:
4685
0
        session->set_state("CONFIGURED");
4686
0
        break;
4687
0
      case TracingSession::State::STARTED:
4688
0
        session->set_is_started(true);
4689
0
        session->set_state("STARTED");
4690
0
        break;
4691
0
      case TracingSession::State::DISABLING_WAITING_STOP_ACKS:
4692
0
        session->set_state("STOP_WAIT");
4693
0
        break;
4694
0
      case TracingSession::State::CLONED_READ_ONLY:
4695
0
        session->set_state("CLONED_READ_ONLY");
4696
0
        break;
4697
0
    }
4698
0
  }
4699
0
  callback(/*success=*/true, svc_state);
4700
0
}
4701
4702
void TracingServiceImpl::ConsumerEndpointImpl::QueryCapabilities(
4703
0
    QueryCapabilitiesCallback callback) {
4704
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4705
0
  TracingServiceCapabilities caps;
4706
0
  caps.set_has_query_capabilities(true);
4707
0
  caps.set_has_trace_config_output_path(true);
4708
0
  caps.set_has_clone_session(true);
4709
0
  caps.add_observable_events(ObservableEvents::TYPE_DATA_SOURCES_INSTANCES);
4710
0
  caps.add_observable_events(ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED);
4711
0
  caps.add_observable_events(ObservableEvents::TYPE_CLONE_TRIGGER_HIT);
4712
0
  static_assert(
4713
0
      ObservableEvents::Type_MAX == ObservableEvents::TYPE_CLONE_TRIGGER_HIT,
4714
0
      "");
4715
0
  callback(caps);
4716
0
}
4717
4718
void TracingServiceImpl::ConsumerEndpointImpl::SaveTraceForBugreport(
4719
0
    SaveTraceForBugreportCallback consumer_callback) {
4720
0
  consumer_callback(false,
4721
0
                    "SaveTraceForBugreport is deprecated. Use "
4722
0
                    "CloneSession(kBugreportSessionId) instead.");
4723
0
}
4724
4725
void TracingServiceImpl::ConsumerEndpointImpl::CloneSession(
4726
0
    CloneSessionArgs args) {
4727
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4728
  // FlushAndCloneSession will call OnSessionCloned after the async flush.
4729
0
  base::Status result = service_->FlushAndCloneSession(this, std::move(args));
4730
4731
0
  if (!result.ok()) {
4732
0
    consumer_->OnSessionCloned({false, result.message(), {}});
4733
0
  }
4734
0
}
4735
4736
////////////////////////////////////////////////////////////////////////////////
4737
// TracingServiceImpl::ProducerEndpointImpl implementation
4738
////////////////////////////////////////////////////////////////////////////////
4739
4740
TracingServiceImpl::ProducerEndpointImpl::ProducerEndpointImpl(
4741
    ProducerID id,
4742
    const ClientIdentity& client_identity,
4743
    TracingServiceImpl* service,
4744
    base::TaskRunner* task_runner,
4745
    Producer* producer,
4746
    const std::string& producer_name,
4747
    const std::string& sdk_version,
4748
    bool in_process,
4749
    bool smb_scraping_enabled)
4750
300
    : id_(id),
4751
300
      client_identity_(client_identity),
4752
300
      service_(service),
4753
300
      producer_(producer),
4754
300
      name_(producer_name),
4755
300
      sdk_version_(sdk_version),
4756
300
      in_process_(in_process),
4757
300
      smb_scraping_enabled_(smb_scraping_enabled),
4758
300
      weak_runner_(task_runner) {}
4759
4760
300
TracingServiceImpl::ProducerEndpointImpl::~ProducerEndpointImpl() {
4761
300
  service_->DisconnectProducer(id_);
4762
300
  producer_->OnDisconnect();
4763
300
}
4764
4765
0
void TracingServiceImpl::ProducerEndpointImpl::Disconnect() {
4766
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4767
  // Disconnection is only supported via destroying the ProducerEndpoint.
4768
0
  PERFETTO_FATAL("Not supported");
4769
0
}
4770
4771
void TracingServiceImpl::ProducerEndpointImpl::RegisterDataSource(
4772
300
    const DataSourceDescriptor& desc) {
4773
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4774
300
  service_->RegisterDataSource(id_, desc);
4775
300
}
4776
4777
void TracingServiceImpl::ProducerEndpointImpl::UpdateDataSource(
4778
0
    const DataSourceDescriptor& desc) {
4779
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4780
0
  service_->UpdateDataSource(id_, desc);
4781
0
}
4782
4783
void TracingServiceImpl::ProducerEndpointImpl::UnregisterDataSource(
4784
0
    const std::string& name) {
4785
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4786
0
  service_->UnregisterDataSource(id_, name);
4787
0
}
4788
4789
void TracingServiceImpl::ProducerEndpointImpl::RegisterTraceWriter(
4790
    uint32_t writer_id,
4791
300
    uint32_t target_buffer) {
4792
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4793
300
  writers_[static_cast<WriterID>(writer_id)] =
4794
300
      static_cast<BufferID>(target_buffer);
4795
300
}
4796
4797
void TracingServiceImpl::ProducerEndpointImpl::UnregisterTraceWriter(
4798
300
    uint32_t writer_id) {
4799
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4800
300
  writers_.erase(static_cast<WriterID>(writer_id));
4801
300
}
4802
4803
void TracingServiceImpl::ProducerEndpointImpl::CommitData(
4804
    const CommitDataRequest& req_untrusted,
4805
1.75k
    CommitDataCallback callback) {
4806
1.75k
  PERFETTO_DCHECK_THREAD(thread_checker_);
4807
4808
1.75k
  if (metatrace::IsEnabled(metatrace::TAG_TRACE_SERVICE)) {
4809
0
    PERFETTO_METATRACE_COUNTER(TAG_TRACE_SERVICE, TRACE_SERVICE_COMMIT_DATA,
4810
0
                               EncodeCommitDataRequest(id_, req_untrusted));
4811
0
  }
4812
4813
1.75k
  if (!shared_memory_) {
4814
0
    PERFETTO_DLOG(
4815
0
        "Attempted to commit data before the shared memory was allocated.");
4816
0
    return;
4817
0
  }
4818
1.75k
  PERFETTO_DCHECK(shmem_abi_.is_valid());
4819
44.6k
  for (const auto& entry : req_untrusted.chunks_to_move()) {
4820
44.6k
    const uint32_t page_idx = entry.page();
4821
44.6k
    if (page_idx >= shmem_abi_.num_pages())
4822
0
      continue;  // A buggy or malicious producer.
4823
4824
44.6k
    SharedMemoryABI::Chunk chunk;
4825
44.6k
    bool commit_data_over_ipc = entry.has_data();
4826
44.6k
    if (PERFETTO_UNLIKELY(commit_data_over_ipc)) {
4827
      // Chunk data is passed over the wire. Create a chunk using the serialized
4828
      // protobuf message.
4829
0
      const std::string& data = entry.data();
4830
0
      if (data.size() > SharedMemoryABI::Chunk::kMaxSize) {
4831
0
        PERFETTO_DFATAL("IPC data commit too large: %zu", data.size());
4832
0
        continue;  // A malicious or buggy producer
4833
0
      }
4834
      // |data| is not altered, but we need to const_cast becasue Chunk data
4835
      // members are non-const.
4836
0
      chunk = SharedMemoryABI::MakeChunkFromSerializedData(
4837
0
          reinterpret_cast<uint8_t*>(const_cast<char*>(data.data())),
4838
0
          static_cast<uint16_t>(entry.data().size()),
4839
0
          static_cast<uint8_t>(entry.chunk()));
4840
0
    } else
4841
44.6k
      chunk = shmem_abi_.TryAcquireChunkForReading(page_idx, entry.chunk());
4842
44.6k
    if (!chunk.is_valid()) {
4843
0
      PERFETTO_DLOG("Asked to move chunk %d:%d, but it's not complete",
4844
0
                    entry.page(), entry.chunk());
4845
0
      continue;
4846
0
    }
4847
4848
    // TryAcquireChunkForReading() has load-acquire semantics. Once acquired,
4849
    // the ABI contract expects the producer to not touch the chunk anymore
4850
    // (until the service marks that as free). This is why all the reads below
4851
    // are just memory_order_relaxed. Also, the code here assumes that all this
4852
    // data can be malicious and just gives up if anything is malformed.
4853
44.6k
    BufferID buffer_id = static_cast<BufferID>(entry.target_buffer());
4854
44.6k
    const SharedMemoryABI::ChunkHeader& chunk_header = *chunk.header();
4855
44.6k
    WriterID writer_id = chunk_header.writer_id.load(std::memory_order_relaxed);
4856
44.6k
    ChunkID chunk_id = chunk_header.chunk_id.load(std::memory_order_relaxed);
4857
44.6k
    auto packets = chunk_header.packets.load(std::memory_order_relaxed);
4858
44.6k
    uint16_t num_fragments = packets.count;
4859
44.6k
    uint8_t chunk_flags = packets.flags;
4860
4861
44.6k
    service_->CopyProducerPageIntoLogBuffer(
4862
44.6k
        id_, client_identity_, writer_id, chunk_id, buffer_id, num_fragments,
4863
44.6k
        chunk_flags,
4864
44.6k
        /*chunk_complete=*/true, chunk.payload_begin(), chunk.payload_size());
4865
4866
44.6k
    if (!commit_data_over_ipc) {
4867
      // This one has release-store semantics.
4868
44.6k
      shmem_abi_.ReleaseChunkAsFree(std::move(chunk));
4869
44.6k
    }
4870
44.6k
  }  // for(chunks_to_move)
4871
4872
1.75k
  service_->ApplyChunkPatches(id_, req_untrusted.chunks_to_patch());
4873
4874
1.75k
  if (req_untrusted.flush_request_id()) {
4875
0
    service_->NotifyFlushDoneForProducer(id_, req_untrusted.flush_request_id());
4876
0
  }
4877
4878
  // Keep this invocation last. ProducerIPCService::CommitData() relies on this
4879
  // callback being invoked within the same callstack and not posted. If this
4880
  // changes, the code there needs to be changed accordingly.
4881
1.75k
  if (callback)
4882
300
    callback();
4883
1.75k
}
4884
4885
void TracingServiceImpl::ProducerEndpointImpl::SetupSharedMemory(
4886
    std::unique_ptr<SharedMemory> shared_memory,
4887
    size_t page_size_bytes,
4888
300
    bool provided_by_producer) {
4889
300
  PERFETTO_DCHECK(!shared_memory_ && !shmem_abi_.is_valid());
4890
300
  PERFETTO_DCHECK(page_size_bytes % 1024 == 0);
4891
4892
300
  shared_memory_ = std::move(shared_memory);
4893
300
  shared_buffer_page_size_kb_ = page_size_bytes / 1024;
4894
300
  is_shmem_provided_by_producer_ = provided_by_producer;
4895
4896
300
  shmem_abi_.Initialize(reinterpret_cast<uint8_t*>(shared_memory_->start()),
4897
300
                        shared_memory_->size(),
4898
300
                        shared_buffer_page_size_kb() * 1024,
4899
300
                        SharedMemoryABI::ShmemMode::kDefault);
4900
300
  if (in_process_) {
4901
0
    inproc_shmem_arbiter_.reset(new SharedMemoryArbiterImpl(
4902
0
        shared_memory_->start(), shared_memory_->size(),
4903
0
        SharedMemoryABI::ShmemMode::kDefault,
4904
0
        shared_buffer_page_size_kb_ * 1024, this, weak_runner_.task_runner()));
4905
0
    inproc_shmem_arbiter_->SetDirectSMBPatchingSupportedByService();
4906
0
  }
4907
4908
300
  OnTracingSetup();
4909
300
  service_->UpdateMemoryGuardrail();
4910
300
}
4911
4912
1.79k
SharedMemory* TracingServiceImpl::ProducerEndpointImpl::shared_memory() const {
4913
1.79k
  PERFETTO_DCHECK_THREAD(thread_checker_);
4914
1.79k
  return shared_memory_.get();
4915
1.79k
}
4916
4917
size_t TracingServiceImpl::ProducerEndpointImpl::shared_buffer_page_size_kb()
4918
600
    const {
4919
600
  return shared_buffer_page_size_kb_;
4920
600
}
4921
4922
void TracingServiceImpl::ProducerEndpointImpl::ActivateTriggers(
4923
0
    const std::vector<std::string>& triggers) {
4924
0
  service_->ActivateTriggers(id_, triggers);
4925
0
}
4926
4927
void TracingServiceImpl::ProducerEndpointImpl::StopDataSource(
4928
300
    DataSourceInstanceID ds_inst_id) {
4929
  // TODO(primiano): When we'll support tearing down the SMB, at this point we
4930
  // should send the Producer a TearDownTracing if all its data sources have
4931
  // been disabled (see b/77532839 and aosp/655179 PS1).
4932
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4933
300
  weak_runner_.PostTask(
4934
300
      [this, ds_inst_id] { producer_->StopDataSource(ds_inst_id); });
4935
300
}
4936
4937
SharedMemoryArbiter*
4938
0
TracingServiceImpl::ProducerEndpointImpl::MaybeSharedMemoryArbiter() {
4939
0
  if (!inproc_shmem_arbiter_) {
4940
0
    PERFETTO_FATAL(
4941
0
        "The in-process SharedMemoryArbiter can only be used when "
4942
0
        "CreateProducer has been called with in_process=true and after tracing "
4943
0
        "has started.");
4944
0
  }
4945
4946
0
  PERFETTO_DCHECK(in_process_);
4947
0
  return inproc_shmem_arbiter_.get();
4948
0
}
4949
4950
bool TracingServiceImpl::ProducerEndpointImpl::IsShmemProvidedByProducer()
4951
600
    const {
4952
600
  return is_shmem_provided_by_producer_;
4953
600
}
4954
4955
// Can be called on any thread.
4956
std::unique_ptr<TraceWriter>
4957
TracingServiceImpl::ProducerEndpointImpl::CreateTraceWriter(
4958
    BufferID buf_id,
4959
0
    BufferExhaustedPolicy buffer_exhausted_policy) {
4960
0
  PERFETTO_DCHECK(MaybeSharedMemoryArbiter());
4961
0
  return MaybeSharedMemoryArbiter()->CreateTraceWriter(buf_id,
4962
0
                                                       buffer_exhausted_policy);
4963
0
}
4964
4965
void TracingServiceImpl::ProducerEndpointImpl::NotifyFlushComplete(
4966
0
    FlushRequestID id) {
4967
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4968
0
  PERFETTO_DCHECK(MaybeSharedMemoryArbiter());
4969
0
  return MaybeSharedMemoryArbiter()->NotifyFlushComplete(id);
4970
0
}
4971
4972
300
void TracingServiceImpl::ProducerEndpointImpl::OnTracingSetup() {
4973
300
  weak_runner_.PostTask([this] { producer_->OnTracingSetup(); });
4974
300
}
4975
4976
void TracingServiceImpl::ProducerEndpointImpl::Flush(
4977
    FlushRequestID flush_request_id,
4978
    const std::vector<DataSourceInstanceID>& data_sources,
4979
0
    FlushFlags flush_flags) {
4980
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
4981
0
  weak_runner_.PostTask([this, flush_request_id, data_sources, flush_flags] {
4982
0
    producer_->Flush(flush_request_id, data_sources.data(), data_sources.size(),
4983
0
                     flush_flags);
4984
0
  });
4985
0
}
4986
4987
void TracingServiceImpl::ProducerEndpointImpl::SetupDataSource(
4988
    DataSourceInstanceID ds_id,
4989
300
    const DataSourceConfig& config) {
4990
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
4991
300
  allowed_target_buffers_.insert(static_cast<BufferID>(config.target_buffer()));
4992
300
  weak_runner_.PostTask([this, ds_id, config] {
4993
300
    producer_->SetupDataSource(ds_id, std::move(config));
4994
300
  });
4995
300
}
4996
4997
void TracingServiceImpl::ProducerEndpointImpl::StartDataSource(
4998
    DataSourceInstanceID ds_id,
4999
300
    const DataSourceConfig& config) {
5000
300
  PERFETTO_DCHECK_THREAD(thread_checker_);
5001
300
  weak_runner_.PostTask([this, ds_id, config] {
5002
300
    producer_->StartDataSource(ds_id, std::move(config));
5003
300
  });
5004
300
}
5005
5006
void TracingServiceImpl::ProducerEndpointImpl::NotifyDataSourceStarted(
5007
0
    DataSourceInstanceID data_source_id) {
5008
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
5009
0
  service_->NotifyDataSourceStarted(id_, data_source_id);
5010
0
}
5011
5012
void TracingServiceImpl::ProducerEndpointImpl::NotifyDataSourceStopped(
5013
0
    DataSourceInstanceID data_source_id) {
5014
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
5015
0
  service_->NotifyDataSourceStopped(id_, data_source_id);
5016
0
}
5017
5018
void TracingServiceImpl::ProducerEndpointImpl::OnFreeBuffers(
5019
0
    const std::vector<BufferID>& target_buffers) {
5020
0
  if (allowed_target_buffers_.empty())
5021
0
    return;
5022
0
  for (BufferID buffer : target_buffers)
5023
0
    allowed_target_buffers_.erase(buffer);
5024
0
}
5025
5026
void TracingServiceImpl::ProducerEndpointImpl::ClearIncrementalState(
5027
0
    const std::vector<DataSourceInstanceID>& data_sources) {
5028
0
  PERFETTO_DCHECK_THREAD(thread_checker_);
5029
0
  weak_runner_.PostTask([this, data_sources] {
5030
0
    base::StringView producer_name(name_);
5031
0
    producer_->ClearIncrementalState(data_sources.data(), data_sources.size());
5032
0
  });
5033
0
}
5034
5035
void TracingServiceImpl::ProducerEndpointImpl::Sync(
5036
0
    std::function<void()> callback) {
5037
0
  weak_runner_.task_runner()->PostTask(callback);
5038
0
}
5039
5040
600
bool TracingServiceImpl::ProducerEndpointImpl::IsAndroidProcessFrozen() {
5041
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
5042
  if (in_process_ || uid() == base::kInvalidUid || pid() == base::kInvalidPid)
5043
    return false;
5044
5045
  // As per aosp/3406861, there are three possible mount points for the cgroup.
5046
  // Look at all of them.
5047
  // - Historically everything was in /uid_xxx/pid_yyy (and still is if
5048
  //   PRODUCT_CGROUP_V2_SYS_APP_ISOLATION_ENABLED = false)
5049
  // - cgroup isolation introduces /apps /system subdirectories.
5050
  base::StackString<255> path_v1(
5051
      "/sys/fs/cgroup/uid_%" PRIu32 "/pid_%" PRIu32 "/cgroup.freeze",
5052
      static_cast<uint32_t>(uid()), static_cast<uint32_t>(pid()));
5053
  base::StackString<255> path_v2_app(
5054
      "/sys/fs/cgroup/apps/uid_%" PRIu32 "/pid_%" PRIu32 "/cgroup.freeze",
5055
      static_cast<uint32_t>(uid()), static_cast<uint32_t>(pid()));
5056
  base::StackString<255> path_v2_system(
5057
      "/sys/fs/cgroup/system/uid_%" PRIu32 "/pid_%" PRIu32 "/cgroup.freeze",
5058
      static_cast<uint32_t>(uid()), static_cast<uint32_t>(pid()));
5059
  const char* paths[] = {path_v1.c_str(), path_v2_app.c_str(),
5060
                         path_v2_system.c_str()};
5061
5062
  for (const char* path : paths) {
5063
    char frozen = '0';
5064
    auto fd = base::OpenFile(path, O_RDONLY);
5065
    ssize_t rsize = 0;
5066
    if (fd) {
5067
      rsize = base::Read(*fd, &frozen, sizeof(frozen));
5068
      if (rsize > 0) {
5069
        return frozen == '1';
5070
      }
5071
    }
5072
  }
5073
  PERFETTO_DLOG("Failed to read cgroup.freeze from [%s, %s, %s]",
5074
                path_v1.c_str(), path_v2_app.c_str(), path_v2_system.c_str());
5075
5076
#endif
5077
600
  return false;
5078
600
}
5079
5080
////////////////////////////////////////////////////////////////////////////////
5081
// TracingServiceImpl::TracingSession implementation
5082
////////////////////////////////////////////////////////////////////////////////
5083
5084
TracingServiceImpl::TracingSession::TracingSession(
5085
    TracingSessionID session_id,
5086
    ConsumerEndpointImpl* consumer,
5087
    const TraceConfig& new_config,
5088
    base::TaskRunner* task_runner)
5089
300
    : id(session_id),
5090
300
      consumer_maybe_null(consumer),
5091
300
      consumer_uid(consumer->uid_),
5092
300
      config(new_config),
5093
300
      snapshot_periodic_task(task_runner),
5094
300
      timed_stop_task(task_runner) {
5095
  // all_data_sources_flushed (and flush_started) is special because we store up
5096
  // to 64 events of this type. Other events will go through the default case in
5097
  // SnapshotLifecycleEvent() where they will be given a max history of 1.
5098
300
  lifecycle_events.emplace_back(
5099
300
      protos::pbzero::TracingServiceEvent::kAllDataSourcesFlushedFieldNumber,
5100
300
      64 /* max_size */);
5101
300
  lifecycle_events.emplace_back(
5102
300
      protos::pbzero::TracingServiceEvent::kFlushStartedFieldNumber,
5103
300
      64 /* max_size */);
5104
300
}
5105
5106
////////////////////////////////////////////////////////////////////////////////
5107
// TracingServiceImpl::RelayEndpointImpl implementation
5108
////////////////////////////////////////////////////////////////////////////////
5109
TracingServiceImpl::RelayEndpointImpl::RelayEndpointImpl(
5110
    RelayClientID relay_client_id,
5111
    TracingServiceImpl* service)
5112
0
    : relay_client_id_(relay_client_id), service_(service) {}
5113
0
TracingServiceImpl::RelayEndpointImpl::~RelayEndpointImpl() = default;
5114
5115
void TracingServiceImpl::RelayEndpointImpl::SyncClocks(
5116
    SyncMode sync_mode,
5117
    base::ClockSnapshotVector client_clocks,
5118
0
    base::ClockSnapshotVector host_clocks) {
5119
  // We keep only the most recent 5 clock sync snapshots.
5120
0
  static constexpr size_t kNumSyncClocks = 5;
5121
0
  if (synced_clocks_.size() >= kNumSyncClocks)
5122
0
    synced_clocks_.pop_front();
5123
5124
0
  synced_clocks_.emplace_back(sync_mode, std::move(client_clocks),
5125
0
                              std::move(host_clocks));
5126
0
}
5127
5128
0
void TracingServiceImpl::RelayEndpointImpl::Disconnect() {
5129
0
  service_->DisconnectRelayClient(relay_client_id_);
5130
0
}
5131
5132
}  // namespace perfetto