File: graphics_memory_dump_provider_android.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (153 lines) | stat: -rw-r--r-- 5,192 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "components/tracing/common/graphics_memory_dump_provider_android.h"

#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

#include <string_view>

#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
#include "base/trace_event/process_memory_dump.h"

using base::trace_event::MemoryAllocatorDump;

namespace tracing {

// static
const char GraphicsMemoryDumpProvider::kDumpBaseName[] =
    "gpu/android_memtrack/";

// static
GraphicsMemoryDumpProvider* GraphicsMemoryDumpProvider::GetInstance() {
  return base::Singleton<
      GraphicsMemoryDumpProvider,
      base::LeakySingletonTraits<GraphicsMemoryDumpProvider>>::get();
}

bool GraphicsMemoryDumpProvider::OnMemoryDump(
    const base::trace_event::MemoryDumpArgs& args,
    base::trace_event::ProcessMemoryDump* pmd) {
  if (args.level_of_detail !=
      base::trace_event::MemoryDumpLevelOfDetail::kDetailed) {
    return true;  // Dump on detailed memory dumps only.
  }

  const char kAbstractSocketName[] = "chrome_tracing_memtrack_helper";
  struct sockaddr_un addr;

  const int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
  if (sock == -1)
    return false;
  // Ensures that sock is always closed, even in case of early returns.
  base::ScopedFD sock_closer(sock);

  // Set recv() timeout to 250 ms.
  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = 250000;
  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

  // Connect to the UNIX abstract (i.e. no physical filesystem link) socket.
  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(&addr.sun_path[1], kAbstractSocketName, sizeof(addr.sun_path) - 2);

  if (connect(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
    LOG(WARNING) << "Could not connect to the memtrack_helper daemon. Please "
                    "build memtrack_helper, adb push to the device and run it "
                    "before starting the trace to get graphics memory data.";
    return false;
  }

  // Check that the socket is owned by root (the memtrack_helper) process and
  // not an (untrusted) user process.
  struct ucred cred;
  socklen_t cred_len = sizeof(cred);
  if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) < 0 ||
      (static_cast<unsigned>(cred_len) < sizeof(cred)) ||
      cred.uid != 0 /* root */) {
    LOG(WARNING) << "Untrusted (!= root) memtrack_helper daemon detected.";
    return false;
  }

  // Send the trace(PID) request.
  char buf[4096];
  const int buf_pid_len = snprintf(buf, sizeof(buf) - 1, "%d", getpid());
  if (HANDLE_EINTR(send(sock, buf, buf_pid_len + 1, 0)) <= 0)
    return false;

  // The response consists of a few lines, each one with a key value pair. E.g.:
  // graphics_total 10616832
  // graphics_pss 10616832
  // gl_total 17911808
  // gl_pss 17911808
  ssize_t rsize;
  if ((rsize = HANDLE_EINTR(recv(sock, buf, sizeof(buf), 0))) <= 0)
    return false;

  buf[sizeof(buf) - 1] = '\0';
  ParseResponseAndAddToDump(buf, static_cast<size_t>(rsize), pmd);
  return true;
}

void GraphicsMemoryDumpProvider::ParseResponseAndAddToDump(
    const char* response,
    size_t length,
    base::trace_event::ProcessMemoryDump* pmd) {
  base::CStringTokenizer tokenizer(response, response + length, " \n");
  while (true) {
    if (!tokenizer.GetNext())
      break;
    std::string_view row_name = tokenizer.token_piece();
    if (!tokenizer.GetNext())
      break;
    std::string_view value_str = tokenizer.token_piece();
    int64_t value;
    if (!base::StringToInt64(value_str, &value) || value < 0)
      continue;  // Skip invalid or negative values.

    // Turn entries like graphics_total into a row named "graphics" and
    // column named "total".
    std::string column_name = "memtrack_";
    size_t key_split_point = row_name.find_last_of('_');
    if (key_split_point > 0 && key_split_point < row_name.size() - 1) {
      column_name.append(row_name.begin() + key_split_point + 1,
                         row_name.end());
      row_name = row_name.substr(0, key_split_point);
    } else {
      column_name += "unknown";
    }

    // Append a row to the memory dump.
    std::string dump_name = base::StrCat({kDumpBaseName, row_name});
    MemoryAllocatorDump* mad = pmd->GetOrCreateAllocatorDump(dump_name);
    const auto& long_lived_column_name = key_names_.insert(column_name).first;
    mad->AddScalar(long_lived_column_name->c_str(),
                   MemoryAllocatorDump::kUnitsBytes, value);
  }
}

GraphicsMemoryDumpProvider::GraphicsMemoryDumpProvider() = default;

GraphicsMemoryDumpProvider::~GraphicsMemoryDumpProvider() = default;

}  // namespace tracing