Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / tools / android / file_poller / file_poller.cc
blobc73db8b6e6f7cd2083ff3587e1c1dc1ddd9efd56
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // When run with 2 or more arguments the file_poller tool will open a port on
6 // the device, print it on its standard output and then start collect file
7 // contents. The first argument is the polling rate in Hz, and the following
8 // arguments are file to poll.
9 // When run with the port of an already running file_poller, the tool will
10 // contact the first instance, retrieve the sample and print those on its
11 // standard output. This will also terminate the first instance.
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <netinet/in.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <unistd.h>
24 #include "base/logging.h"
26 // Context containing the files to poll and the polling rate.
27 struct Context {
28 size_t nb_files;
29 int* file_fds;
30 int poll_rate;
33 // Write from the buffer to the given file descriptor.
34 void safe_write(int fd, const char* buffer, int size) {
35 const char* index = buffer;
36 size_t to_write = size;
37 while (to_write > 0) {
38 int written = write(fd, index, to_write);
39 if (written < 0)
40 PLOG(FATAL);
41 index += written;
42 to_write -= written;
46 // Transfer the content of a file descriptor to another.
47 void transfer_to_fd(int fd_in, int fd_out) {
48 char buffer[1024];
49 int n;
50 while ((n = read(fd_in, buffer, sizeof(buffer))) > 0)
51 safe_write(fd_out, buffer, n);
54 // Transfer the content of a file descriptor to a buffer.
55 int transfer_to_buffer(int fd_in, char* bufffer, size_t size) {
56 char* index = bufffer;
57 size_t to_read = size;
58 int n;
59 while (to_read > 0 && ((n = read(fd_in, index, to_read)) > 0)) {
60 index += n;
61 to_read -= n;
63 if (n < 0)
64 PLOG(FATAL);
65 return size - to_read;
68 // Try to open the file at the given path for reading. Exit in case of failure.
69 int checked_open(const char* path) {
70 int fd = open(path, O_RDONLY);
71 if (fd < 0)
72 PLOG(FATAL);
73 return fd;
76 void transfer_measurement(int fd_in, int fd_out, bool last) {
77 char buffer[1024];
78 if (lseek(fd_in, 0, SEEK_SET) < 0)
79 PLOG(FATAL);
80 int n = transfer_to_buffer(fd_in, buffer, sizeof(buffer));
81 safe_write(fd_out, buffer, n - 1);
82 safe_write(fd_out, last ? "\n" : " ", 1);
85 // Acquire a sample and save it to the given file descriptor.
86 void acquire_sample(int fd, const Context& context) {
87 struct timeval tv;
88 gettimeofday(&tv, NULL);
89 char buffer[1024];
90 int n = snprintf(buffer, sizeof(buffer), "%d.%06d ", tv.tv_sec, tv.tv_usec);
91 safe_write(fd, buffer, n);
93 for (int i = 0; i < context.nb_files; ++i)
94 transfer_measurement(context.file_fds[i], fd, i == (context.nb_files - 1));
97 void poll_content(const Context& context) {
98 // Create and bind the socket so that the port can be written to stdout.
99 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
100 struct sockaddr_in socket_info;
101 socket_info.sin_family = AF_INET;
102 socket_info.sin_addr.s_addr = htonl(INADDR_ANY);
103 socket_info.sin_port = htons(0);
104 if (bind(sockfd, (struct sockaddr*)&socket_info, sizeof(socket_info)) < 0)
105 PLOG(FATAL);
106 socklen_t size = sizeof(socket_info);
107 getsockname(sockfd, (struct sockaddr*)&socket_info, &size);
108 printf("%d\n", ntohs(socket_info.sin_port));
109 // Using a pipe to ensure child is diconnected from the terminal before
110 // quitting.
111 int pipes[2];
112 pipe(pipes);
113 pid_t pid = fork();
114 if (pid < 0)
115 PLOG(FATAL);
116 if (pid != 0) {
117 close(pipes[1]);
118 // Not expecting any data to be received.
119 read(pipes[0], NULL, 1);
120 signal(SIGCHLD, SIG_IGN);
121 return;
124 // Detach from terminal.
125 setsid();
126 close(STDIN_FILENO);
127 close(STDOUT_FILENO);
128 close(STDERR_FILENO);
129 close(pipes[0]);
131 // Start listening for incoming connection.
132 if (listen(sockfd, 1) < 0)
133 PLOG(FATAL);
135 // Signal the parent that it can now safely exit.
136 close(pipes[1]);
138 // Prepare file to store the samples.
139 int fd;
140 char filename[] = "/data/local/tmp/fileXXXXXX";
141 fd = mkstemp(filename);
142 unlink(filename);
144 // Collect samples until a client connect on the socket.
145 fd_set rfds;
146 struct timeval timeout;
147 do {
148 acquire_sample(fd, context);
149 timeout.tv_sec = 0;
150 timeout.tv_usec = 1000000 / context.poll_rate;
151 FD_ZERO(&rfds);
152 FD_SET(sockfd, &rfds);
153 } while (select(sockfd + 1, &rfds, NULL, NULL, &timeout) == 0);
155 // Collect a final sample.
156 acquire_sample(fd, context);
158 // Send the result back.
159 struct sockaddr_in remote_socket_info;
160 int rfd = accept(sockfd, (struct sockaddr*)&remote_socket_info, &size);
161 if (rfd < 0)
162 PLOG(FATAL);
163 if (lseek(fd, 0, SEEK_SET) < 0)
164 PLOG(FATAL);
165 transfer_to_fd(fd, rfd);
168 void content_collection(int port) {
169 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
170 // Connect to localhost.
171 struct sockaddr_in socket_info;
172 socket_info.sin_family = AF_INET;
173 socket_info.sin_addr.s_addr = htonl(0x7f000001);
174 socket_info.sin_port = htons(port);
175 if (connect(sockfd, (struct sockaddr*)&socket_info, sizeof(socket_info)) <
176 0) {
177 PLOG(FATAL);
179 transfer_to_fd(sockfd, STDOUT_FILENO);
182 int main(int argc, char** argv) {
183 if (argc == 1) {
184 fprintf(stderr,
185 "Usage: \n"
186 " %s port\n"
187 " %s rate FILE...\n",
188 argv[0],
189 argv[0]);
190 exit(EXIT_FAILURE);
192 if (argc == 2) {
193 // Argument is the port to connect to.
194 content_collection(atoi(argv[1]));
195 } else {
196 // First argument is the poll frequency, in Hz, following arguments are the
197 // file to poll.
198 Context context;
199 context.poll_rate = atoi(argv[1]);
200 context.nb_files = argc - 2;
201 context.file_fds = new int[context.nb_files];
202 for (int i = 2; i < argc; ++i)
203 context.file_fds[i - 2] = checked_open(argv[i]);
204 poll_content(context);
206 return EXIT_SUCCESS;