blob: b118557351d4cdc73952252076e04aee389a1aaa [file] [log] [blame]
primianoeca5bca22015-10-12 09:53:141/*
2 * Copyright 2015 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include "tools/android/memtrack_helper/memtrack_helper.h"
8
9#include <dlfcn.h>
10#include <errno.h>
11#include <fcntl.h>
primianoeca5bca22015-10-12 09:53:1412#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
primianoeca5bca22015-10-12 09:53:1415#include <sys/socket.h>
16#include <sys/un.h>
17#include <sys/stat.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20
21/*
22 * This is a helper daemon for Android which makes memtrack graphics information
23 * accessible via a UNIX socket. It is used by telemetry and memory-infra.
24 * More description in the design-doc: https://goo.gl/4Y30p9 .
25 */
26
27static const char kShutdownRequest = 'Q';
28
29// See $ANDROID/system/core/include/memtrack/memtrack.h.
30typedef void* memtrack_proc_handle;
31typedef int (*memtrack_init_t)(void);
32typedef memtrack_proc_handle (*memtrack_proc_new_t)(void);
33typedef void (*memtrack_proc_destroy_t)(memtrack_proc_handle);
34typedef int (*memtrack_proc_get_t)(memtrack_proc_handle, pid_t);
35typedef ssize_t (*memtrack_proc_graphics_total_t)(memtrack_proc_handle);
36typedef ssize_t (*memtrack_proc_graphics_pss_t)(memtrack_proc_handle);
37typedef ssize_t (*memtrack_proc_gl_total_t)(memtrack_proc_handle);
38typedef ssize_t (*memtrack_proc_gl_pss_t)(memtrack_proc_handle);
39typedef ssize_t (*memtrack_proc_other_total_t)(memtrack_proc_handle);
40typedef ssize_t (*memtrack_proc_other_pss_t)(memtrack_proc_handle);
41
42static memtrack_init_t memtrack_init;
43static memtrack_proc_new_t memtrack_proc_new;
44static memtrack_proc_destroy_t memtrack_proc_destroy;
45static memtrack_proc_get_t memtrack_proc_get;
46static memtrack_proc_graphics_total_t memtrack_proc_graphics_total;
47static memtrack_proc_graphics_pss_t memtrack_proc_graphics_pss;
48static memtrack_proc_gl_total_t memtrack_proc_gl_total;
49static memtrack_proc_gl_pss_t memtrack_proc_gl_pss;
50static memtrack_proc_other_total_t memtrack_proc_other_total;
51static memtrack_proc_other_pss_t memtrack_proc_other_pss;
52
53static void send_response(int client_sock, const char* resp) {
54 send(client_sock, resp, strlen(resp) + 1, 0);
55}
56
57static void send_shutdown_request(struct sockaddr_un* addr) {
58 int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
59 connect(sock, (struct sockaddr*)addr, sizeof(*addr));
60 send(sock, &kShutdownRequest, 1, 0);
61 close(sock);
62}
63
64static void handle_one_request(int client_sock) {
65 char buf[32];
66 char response[4096] = "";
kraynov8bd5c582016-12-15 16:19:3867 ssize_t rsize = recv(client_sock, buf, sizeof(buf) - 1, 0);
primianoeca5bca22015-10-12 09:53:1468 if (rsize < 1)
69 return;
kraynov8bd5c582016-12-15 16:19:3870 buf[rsize] = '\0';
primianoeca5bca22015-10-12 09:53:1471
72 if (buf[0] == kShutdownRequest)
73 exit(EXIT_SUCCESS);
74
75 pid_t pid = -1;
kraynov8bd5c582016-12-15 16:19:3876 if (sscanf(buf, "%d", &pid) != 1 || pid < 0)
primianoeca5bca22015-10-12 09:53:1477 return send_response(client_sock, "ERR invalid pid");
78
79 memtrack_proc_handle handle = memtrack_proc_new();
80 if (!handle)
81 return send_response(client_sock, "ERR memtrack_proc_new()");
82
83 if (memtrack_proc_get(handle, pid)) {
84 memtrack_proc_destroy(handle);
85 return send_response(client_sock, "ERR memtrack_proc_get()");
86 }
87
88 char* response_ptr = &response[0];
89 if (memtrack_proc_graphics_total) {
90 response_ptr += sprintf(response_ptr, "graphics_total %zd\n",
91 memtrack_proc_graphics_total(handle));
92 }
93 if (memtrack_proc_graphics_pss) {
94 response_ptr += sprintf(response_ptr, "graphics_pss %zd\n",
95 memtrack_proc_graphics_pss(handle));
96 }
97 if (memtrack_proc_gl_total) {
kraynov8bd5c582016-12-15 16:19:3898 response_ptr += sprintf(response_ptr, "gl_total %zd\n",
99 memtrack_proc_gl_total(handle));
primianoeca5bca22015-10-12 09:53:14100 }
101 if (memtrack_proc_gl_pss) {
kraynov8bd5c582016-12-15 16:19:38102 response_ptr += sprintf(response_ptr, "gl_pss %zd\n",
103 memtrack_proc_gl_pss(handle));
primianoeca5bca22015-10-12 09:53:14104 }
105 if (memtrack_proc_other_total) {
106 response_ptr += sprintf(response_ptr, "other_total %zd\n",
107 memtrack_proc_other_total(handle));
108 }
109 if (memtrack_proc_other_pss) {
110 response_ptr += sprintf(response_ptr, "other_pss %zd\n",
111 memtrack_proc_other_pss(handle));
112 }
113
114 memtrack_proc_destroy(handle);
115 send_response(client_sock, response);
116}
117
118static void daemonize() {
119 pid_t pid;
120
121 pid = fork();
122 if (pid < 0)
123 exit_with_failure("fork");
124 if (pid > 0) {
kraynov8bd5c582016-12-15 16:19:38125 // Main process keeps TTY while intermediate child do daemonization
126 // because adb can immediately kill a process disconnected from adb's TTY.
primianoeca5bca22015-10-12 09:53:14127 int ignore;
128 wait(&ignore);
129 exit(EXIT_SUCCESS);
130 }
131
132 if (setsid() == -1)
133 exit_with_failure("setsid");
134
135 chdir("/");
136 umask(0);
137 close(STDIN_FILENO);
138 close(STDOUT_FILENO);
139 close(STDERR_FILENO);
140 open("/dev/null", O_RDONLY);
141 open("/dev/null", O_WRONLY);
142 open("/dev/null", O_RDWR);
143
144 pid = fork();
145 if (pid < 0)
146 exit_with_failure("fork");
147 if (pid > 0)
148 exit(EXIT_SUCCESS);
149}
150
151int main(int argc, char** argv) {
152 int res;
153
154 if (getuid() != 0) {
155 fprintf(stderr, "FATAL: %s must be run as root!\n", argv[0]);
156 return EXIT_FAILURE;
157 }
158
159 void* const libhandle = dlopen("libmemtrack.so", RTLD_GLOBAL | RTLD_NOW);
160 if (!libhandle)
161 exit_with_failure("dlopen() libmemtrack.so");
162 memtrack_init = (memtrack_init_t)dlsym(libhandle, "memtrack_init");
163 memtrack_proc_new =
164 (memtrack_proc_new_t)dlsym(libhandle, "memtrack_proc_new");
165 memtrack_proc_destroy =
166 (memtrack_proc_destroy_t)dlsym(libhandle, "memtrack_proc_destroy");
167 memtrack_proc_get =
168 (memtrack_proc_get_t)dlsym(libhandle, "memtrack_proc_get");
169 memtrack_proc_graphics_total = (memtrack_proc_graphics_total_t)dlsym(
170 libhandle, "memtrack_proc_graphics_total");
171 memtrack_proc_graphics_pss = (memtrack_proc_graphics_pss_t)dlsym(
172 libhandle, "memtrack_proc_graphics_pss");
173 memtrack_proc_gl_total =
174 (memtrack_proc_gl_total_t)dlsym(libhandle, "memtrack_proc_gl_total");
175 memtrack_proc_gl_pss =
176 (memtrack_proc_gl_pss_t)dlsym(libhandle, "memtrack_proc_gl_pss");
177 memtrack_proc_other_total = (memtrack_proc_other_total_t)dlsym(
178 libhandle, "memtrack_proc_other_total");
179 memtrack_proc_other_pss =
180 (memtrack_proc_other_pss_t)dlsym(libhandle, "memtrack_proc_other_pss");
181
kraynov8bd5c582016-12-15 16:19:38182 if (!memtrack_proc_new || !memtrack_proc_destroy || !memtrack_proc_get) {
primianoeca5bca22015-10-12 09:53:14183 exit_with_failure("dlsym() libmemtrack.so");
184 }
185
186 const int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
187 if (server_fd < 0)
188 exit_with_failure("socket");
189
190 /* Initialize the socket */
191 struct sockaddr_un server_addr;
192 init_memtrack_server_addr(&server_addr);
193
194 /* Shutdown previously running instances if any. */
195 int i;
196 for (i = 0; i < 3; ++i) {
197 res = bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
198 if (res && errno == EADDRINUSE) {
199 send_shutdown_request(&server_addr);
200 usleep(250000);
201 continue;
202 }
203 break;
204 }
205
206 if (res)
207 exit_with_failure("bind");
208
209 if (argc > 1 && strcmp(argv[1], "-d") == 0)
210 daemonize();
211
kraynov8bd5c582016-12-15 16:19:38212 long pid = getpid();
213 fprintf(stderr, "pid=%ld\n", pid);
214 __android_log_print(ANDROID_LOG_INFO, kLogTag, "pid=%ld\n", pid);
215
216 if (memtrack_init) {
217 res = memtrack_init();
218 if (res == -ENOENT) {
219 exit_with_failure("Unable to load memtrack module in libhardware. "
220 "Probably implementation is missing in this ROM.");
221 } else if (res != 0) {
222 exit_with_failure("memtrack_init() returned non-zero status.");
223 }
kraynove6d5e13c2016-10-06 14:59:34224 }
primianoeca5bca22015-10-12 09:53:14225
226 if (listen(server_fd, 128 /* max number of queued requests */))
227 exit_with_failure("listen");
228
229 for (;;) {
230 struct sockaddr_un client_addr;
231 socklen_t len = sizeof(client_addr);
232 int client_sock = accept(server_fd, (struct sockaddr*)&client_addr, &len);
233 handle_one_request(client_sock);
234 close(client_sock);
235 }
236
237 return EXIT_SUCCESS;
238}