blob: 517da55f58671dbb78707abff8da9f2f6c6fc955 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 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 <stdlib.h>
18#include <stdio.h>
19#include <unistd.h>
20#include <string.h>
21#include <errno.h>
22
23#include "sysdeps.h"
24
25#define TRACE_TAG TRACE_ADB
26#include "adb.h"
27#include "file_sync_service.h"
28
29#if ADB_HOST
30# ifndef HAVE_WINSOCK
31# include <netinet/in.h>
32# include <netdb.h>
33# endif
Mike Lockwoodcc1de482009-07-30 16:23:56 -070034#else
35#include <sys/poll.h>
Mike Lockwoodee156622009-08-04 20:37:51 -040036#include <sys/reboot.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037#endif
38
39typedef struct stinfo stinfo;
40
41struct stinfo {
42 void (*func)(int fd, void *cookie);
43 int fd;
44 void *cookie;
45};
46
47
48void *service_bootstrap_func(void *x)
49{
50 stinfo *sti = x;
51 sti->func(sti->fd, sti->cookie);
52 free(sti);
53 return 0;
54}
55
56#if ADB_HOST
57ADB_MUTEX_DEFINE( dns_lock );
58
59static void dns_service(int fd, void *cookie)
60{
61 char *hostname = cookie;
62 struct hostent *hp;
63 unsigned zero = 0;
64
65 adb_mutex_lock(&dns_lock);
66 hp = gethostbyname(hostname);
67 if(hp == 0) {
68 writex(fd, &zero, 4);
69 } else {
70 writex(fd, hp->h_addr, 4);
71 }
72 adb_mutex_unlock(&dns_lock);
73 adb_close(fd);
74}
75#else
76extern int recovery_mode;
77
78static void recover_service(int s, void *cookie)
79{
80 unsigned char buf[4096];
81 unsigned count = (unsigned) cookie;
82 int fd;
83
84 fd = adb_creat("/tmp/update", 0644);
85 if(fd < 0) {
86 adb_close(s);
87 return;
88 }
89
90 while(count > 0) {
91 unsigned xfer = (count > 4096) ? 4096 : count;
92 if(readx(s, buf, xfer)) break;
93 if(writex(fd, buf, xfer)) break;
94 count -= xfer;
95 }
96
97 if(count == 0) {
98 writex(s, "OKAY", 4);
99 } else {
100 writex(s, "FAIL", 4);
101 }
102 adb_close(fd);
103 adb_close(s);
104
105 fd = adb_creat("/tmp/update.begin", 0644);
106 adb_close(fd);
107}
108
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700109void restart_root_service(int fd, void *cookie)
110{
111 char buf[100];
112 char value[PROPERTY_VALUE_MAX];
113
114 if (getuid() == 0) {
115 snprintf(buf, sizeof(buf), "adbd is already running as root\n");
116 writex(fd, buf, strlen(buf));
117 adb_close(fd);
118 } else {
119 property_get("ro.debuggable", value, "");
120 if (strcmp(value, "1") != 0) {
121 snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
122 writex(fd, buf, strlen(buf));
123 return;
124 }
125
126 property_set("service.adb.root", "1");
127 snprintf(buf, sizeof(buf), "restarting adbd as root\n");
128 writex(fd, buf, strlen(buf));
129 adb_close(fd);
130
131 // quit, and init will restart us as root
132 sleep(1);
133 exit(1);
134 }
135}
136
Mike Lockwoodee156622009-08-04 20:37:51 -0400137void reboot_service(int fd, char *arg)
138{
139 char buf[100];
140 int ret;
141
142 sync();
143 ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg);
144 if (ret < 0) {
145 snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
146 writex(fd, buf, strlen(buf));
147 }
148 adb_close(fd);
149}
150
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800151#endif
152
153#if 0
154static void echo_service(int fd, void *cookie)
155{
156 char buf[4096];
157 int r;
158 char *p;
159 int c;
160
161 for(;;) {
162 r = read(fd, buf, 4096);
163 if(r == 0) goto done;
164 if(r < 0) {
165 if(errno == EINTR) continue;
166 else goto done;
167 }
168
169 c = r;
170 p = buf;
171 while(c > 0) {
172 r = write(fd, p, c);
173 if(r > 0) {
174 c -= r;
175 p += r;
176 continue;
177 }
178 if((r < 0) && (errno == EINTR)) continue;
179 goto done;
180 }
181 }
182done:
183 close(fd);
184}
185#endif
186
187static int create_service_thread(void (*func)(int, void *), void *cookie)
188{
189 stinfo *sti;
190 adb_thread_t t;
191 int s[2];
192
193 if(adb_socketpair(s)) {
194 printf("cannot create service socket pair\n");
195 return -1;
196 }
197
198 sti = malloc(sizeof(stinfo));
199 if(sti == 0) fatal("cannot allocate stinfo");
200 sti->func = func;
201 sti->cookie = cookie;
202 sti->fd = s[1];
203
204 if(adb_thread_create( &t, service_bootstrap_func, sti)){
205 free(sti);
206 adb_close(s[0]);
207 adb_close(s[1]);
208 printf("cannot create service thread\n");
209 return -1;
210 }
211
212 D("service thread started, %d:%d\n",s[0], s[1]);
213 return s[0];
214}
215
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700216#if !ADB_HOST
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800217static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
218{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800219 char *devname;
220 int ptm;
221 pid_t pid;
222
223 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
224 if(ptm < 0){
225 printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
226 return -1;
227 }
228 fcntl(ptm, F_SETFD, FD_CLOEXEC);
229
230 if(grantpt(ptm) || unlockpt(ptm) ||
231 ((devname = (char*) ptsname(ptm)) == 0)){
232 printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
233 return -1;
234 }
235
236 pid = fork();
237 if(pid < 0) {
238 printf("- fork failed: %s -\n", strerror(errno));
239 return -1;
240 }
241
242 if(pid == 0){
243 int pts;
244
245 setsid();
246
247 pts = unix_open(devname, O_RDWR);
248 if(pts < 0) exit(-1);
249
250 dup2(pts, 0);
251 dup2(pts, 1);
252 dup2(pts, 2);
253
254 adb_close(ptm);
255
256 execl(cmd, cmd, arg0, arg1, NULL);
257 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
258 cmd, strerror(errno), errno);
259 exit(-1);
260 } else {
Mike Lockwood249ad572009-05-20 09:14:30 -0400261 // set child's OOM adjustment to zero
262 char text[64];
263 snprintf(text, sizeof text, "/proc/%d/oom_adj", pid);
264 int fd = adb_open(text, O_WRONLY);
265 if (fd >= 0) {
266 adb_write(fd, "0", 1);
267 adb_close(fd);
268 } else {
269 D("adb: unable to open %s\n", text);
270 }
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700271
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800272 return ptm;
273 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800274}
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700275#endif /* !ADB_HOST */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800276
277#if ADB_HOST
278#define SHELL_COMMAND "/bin/sh"
279#else
280#define SHELL_COMMAND "/system/bin/sh"
281#endif
282
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700283#if !ADB_HOST
284static void shell_service(int s, void *command)
285{
286 char buffer[MAX_PAYLOAD];
287 char buffer2[MAX_PAYLOAD];
288 struct pollfd ufds[2];
289 int fd, ret = 0;
290 unsigned count = 0;
291 char** args = (char **)command;
292 fd = create_subprocess(SHELL_COMMAND, args[0], args[1]);
293
294 while (1) {
295 while (count < sizeof(buffer)) {
296 ufds[0].fd = fd;
297 ufds[0].events = POLLIN | POLLHUP;
298 ufds[0].revents = 0;
299 ufds[1].fd = s;
300 ufds[1].events = POLLIN | POLLHUP;
301 ufds[1].revents = 0;
302 // use a 100ms timeout so we don't block indefinitely with our
303 // buffer partially filled.
304 ret = poll(ufds, 2, 100);
305 if (ret <= 0) {
306 D("poll returned %d\n", ret);
307 // file has closed or we timed out
308 // set ret to 1 so we don't exit the outer loop
309 ret = 1;
310 break;
311 }
312
313 if (ufds[0].revents & POLLIN) {
314 ret = adb_read(fd, buffer + count, sizeof(buffer) - count);
315 D("read fd ret: %d, count: %d\n", ret, count);
316 if (ret > 0)
317 count += ret;
318 else
319 break;
320 }
321 if (ufds[1].revents & POLLIN) {
322 ret = adb_read(s, buffer2, sizeof(buffer2));
323 D("read s ret: %d\n", ret);
324 if (ret > 0)
325 adb_write(fd, buffer2, ret);
326 else
327 break;
328 }
329
330 if ((ufds[0].revents & POLLHUP) || (ufds[1].revents & POLLHUP)) {
331 // set flag to exit after flushing the buffer
332 ret = -1;
333 break;
334 }
335 }
336
337 D("writing: %d\n", count);
338 if (count > 0) {
339 adb_write(s, buffer, count);
340 count = 0;
341 }
342 if (ret <= 0)
343 break;
344 }
345
346 D("shell_service done\n");
347
348 adb_close(fd);
349 adb_close(s);
350}
351#endif // !ADB_HOST
352
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800353int service_to_fd(const char *name)
354{
355 int ret = -1;
356
357 if(!strncmp(name, "tcp:", 4)) {
358 int port = atoi(name + 4);
359 name = strchr(name + 4, ':');
360 if(name == 0) {
361 ret = socket_loopback_client(port, SOCK_STREAM);
362 if (ret >= 0)
363 disable_tcp_nagle(ret);
364 } else {
365#if ADB_HOST
366 adb_mutex_lock(&dns_lock);
367 ret = socket_network_client(name + 1, port, SOCK_STREAM);
368 adb_mutex_unlock(&dns_lock);
369#else
370 return -1;
371#endif
372 }
373#ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
374 } else if(!strncmp(name, "local:", 6)) {
375 ret = socket_local_client(name + 6,
376 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
377 } else if(!strncmp(name, "localreserved:", 14)) {
378 ret = socket_local_client(name + 14,
379 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
380 } else if(!strncmp(name, "localabstract:", 14)) {
381 ret = socket_local_client(name + 14,
382 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
383 } else if(!strncmp(name, "localfilesystem:", 16)) {
384 ret = socket_local_client(name + 16,
385 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
386#endif
387#if ADB_HOST
388 } else if(!strncmp("dns:", name, 4)){
389 char *n = strdup(name + 4);
390 if(n == 0) return -1;
391 ret = create_service_thread(dns_service, n);
392#else /* !ADB_HOST */
393 } else if(!strncmp("dev:", name, 4)) {
394 ret = unix_open(name + 4, O_RDWR);
395 } else if(!strncmp(name, "framebuffer:", 12)) {
396 ret = create_service_thread(framebuffer_service, 0);
397 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
398 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
399 } else if (!strncmp(name, "jdwp:", 5)) {
400 ret = create_jdwp_connection_fd(atoi(name+5));
401 } else if (!strncmp(name, "log:", 4)) {
402 ret = create_service_thread(log_service, get_log_file_path(name + 4));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800403 } else if(!HOST && !strncmp(name, "shell:", 6)) {
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700404 const char* args[2];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800405 if(name[6]) {
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700406 args[0] = "-c";
407 args[1] = name + 6;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800408 } else {
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700409 args[0] = "-";
410 args[1] = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800411 }
Mike Lockwoodcc1de482009-07-30 16:23:56 -0700412 ret = create_service_thread(shell_service, (void *)args);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800413 } else if(!strncmp(name, "sync:", 5)) {
414 ret = create_service_thread(file_sync_service, NULL);
415 } else if(!strncmp(name, "remount:", 8)) {
416 ret = create_service_thread(remount_service, NULL);
Mike Lockwoodee156622009-08-04 20:37:51 -0400417 } else if(!strncmp(name, "reboot:", 7)) {
418 char* arg = name + 7;
419 if (*name == 0)
420 arg = NULL;
421 ret = create_service_thread(reboot_service, arg);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700422 } else if(!strncmp(name, "root:", 5)) {
423 ret = create_service_thread(restart_root_service, NULL);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800424#endif
425#if 0
426 } else if(!strncmp(name, "echo:", 5)){
427 ret = create_service_thread(echo_service, 0);
428#endif
429 }
430 if (ret >= 0) {
431 close_on_exec(ret);
432 }
433 return ret;
434}
435
436#if ADB_HOST
437struct state_info {
438 transport_type transport;
439 char* serial;
440 int state;
441};
442
443static void wait_for_state(int fd, void* cookie)
444{
445 struct state_info* sinfo = cookie;
446 char* err = "unknown error";
447
448 D("wait_for_state %d\n", sinfo->state);
449
450 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
451 if(t != 0) {
452 writex(fd, "OKAY", 4);
453 } else {
454 sendfailmsg(fd, err);
455 }
456
457 if (sinfo->serial)
458 free(sinfo->serial);
459 free(sinfo);
460 adb_close(fd);
461 D("wait_for_state is done\n");
462}
463#endif
464
465#if ADB_HOST
466asocket* host_service_to_socket(const char* name, const char *serial)
467{
468 if (!strcmp(name,"track-devices")) {
469 return create_device_tracker();
470 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
471 struct state_info* sinfo = malloc(sizeof(struct state_info));
472
473 if (serial)
474 sinfo->serial = strdup(serial);
475 else
476 sinfo->serial = NULL;
477
478 name += strlen("wait-for-");
479
480 if (!strncmp(name, "local", strlen("local"))) {
481 sinfo->transport = kTransportLocal;
482 sinfo->state = CS_DEVICE;
483 } else if (!strncmp(name, "usb", strlen("usb"))) {
484 sinfo->transport = kTransportUsb;
485 sinfo->state = CS_DEVICE;
486 } else if (!strncmp(name, "any", strlen("any"))) {
487 sinfo->transport = kTransportAny;
488 sinfo->state = CS_DEVICE;
489 } else {
490 free(sinfo);
491 return NULL;
492 }
493
494 int fd = create_service_thread(wait_for_state, sinfo);
495 return create_local_socket(fd);
496 }
497 return NULL;
498}
499#endif /* ADB_HOST */