blob: cd02b3667950dcf1a48d1247f11c0a0fab33e9c0 [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
Joe Onorato91acb142009-09-03 16:30:43 -070035# include <sys/reboot.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#endif
37
38typedef struct stinfo stinfo;
39
40struct stinfo {
41 void (*func)(int fd, void *cookie);
42 int fd;
43 void *cookie;
44};
45
46
47void *service_bootstrap_func(void *x)
48{
49 stinfo *sti = x;
50 sti->func(sti->fd, sti->cookie);
51 free(sti);
52 return 0;
53}
54
55#if ADB_HOST
56ADB_MUTEX_DEFINE( dns_lock );
57
58static void dns_service(int fd, void *cookie)
59{
60 char *hostname = cookie;
61 struct hostent *hp;
62 unsigned zero = 0;
63
64 adb_mutex_lock(&dns_lock);
65 hp = gethostbyname(hostname);
66 if(hp == 0) {
67 writex(fd, &zero, 4);
68 } else {
69 writex(fd, hp->h_addr, 4);
70 }
71 adb_mutex_unlock(&dns_lock);
72 adb_close(fd);
73}
74#else
75extern int recovery_mode;
76
77static void recover_service(int s, void *cookie)
78{
79 unsigned char buf[4096];
80 unsigned count = (unsigned) cookie;
81 int fd;
82
83 fd = adb_creat("/tmp/update", 0644);
84 if(fd < 0) {
85 adb_close(s);
86 return;
87 }
88
89 while(count > 0) {
90 unsigned xfer = (count > 4096) ? 4096 : count;
91 if(readx(s, buf, xfer)) break;
92 if(writex(fd, buf, xfer)) break;
93 count -= xfer;
94 }
95
96 if(count == 0) {
97 writex(s, "OKAY", 4);
98 } else {
99 writex(s, "FAIL", 4);
100 }
101 adb_close(fd);
102 adb_close(s);
103
104 fd = adb_creat("/tmp/update.begin", 0644);
105 adb_close(fd);
106}
107
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700108void restart_root_service(int fd, void *cookie)
109{
110 char buf[100];
111 char value[PROPERTY_VALUE_MAX];
112
113 if (getuid() == 0) {
114 snprintf(buf, sizeof(buf), "adbd is already running as root\n");
115 writex(fd, buf, strlen(buf));
116 adb_close(fd);
117 } else {
118 property_get("ro.debuggable", value, "");
119 if (strcmp(value, "1") != 0) {
120 snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
121 writex(fd, buf, strlen(buf));
Mike Lockwoodff196702009-08-24 15:58:40 -0700122 adb_close(fd);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700123 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 Lockwoodff196702009-08-24 15:58:40 -0700137void restart_tcp_service(int fd, void *cookie)
138{
139 char buf[100];
140 char value[PROPERTY_VALUE_MAX];
141 int port = (int)cookie;
142
143 if (port <= 0) {
144 snprintf(buf, sizeof(buf), "invalid port\n");
145 writex(fd, buf, strlen(buf));
146 adb_close(fd);
147 return;
148 }
149
150 snprintf(value, sizeof(value), "%d", port);
151 property_set("service.adb.tcp.port", value);
152 snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
153 writex(fd, buf, strlen(buf));
154 adb_close(fd);
155
156 // quit, and init will restart us in TCP mode
157 sleep(1);
158 exit(1);
159}
160
161void restart_usb_service(int fd, void *cookie)
162{
163 char buf[100];
164
165 property_set("service.adb.tcp.port", "0");
166 snprintf(buf, sizeof(buf), "restarting in USB mode\n");
167 writex(fd, buf, strlen(buf));
168 adb_close(fd);
169
170 // quit, and init will restart us in USB mode
171 sleep(1);
172 exit(1);
173}
174
175void reboot_service(int fd, void *arg)
Mike Lockwoodee156622009-08-04 20:37:51 -0400176{
177 char buf[100];
178 int ret;
179
180 sync();
Mike Lockwoodff196702009-08-24 15:58:40 -0700181 ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
182 LINUX_REBOOT_CMD_RESTART2, (char *)arg);
Mike Lockwoodee156622009-08-04 20:37:51 -0400183 if (ret < 0) {
184 snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
185 writex(fd, buf, strlen(buf));
186 }
187 adb_close(fd);
188}
189
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800190#endif
191
192#if 0
193static void echo_service(int fd, void *cookie)
194{
195 char buf[4096];
196 int r;
197 char *p;
198 int c;
199
200 for(;;) {
201 r = read(fd, buf, 4096);
202 if(r == 0) goto done;
203 if(r < 0) {
204 if(errno == EINTR) continue;
205 else goto done;
206 }
207
208 c = r;
209 p = buf;
210 while(c > 0) {
211 r = write(fd, p, c);
212 if(r > 0) {
213 c -= r;
214 p += r;
215 continue;
216 }
217 if((r < 0) && (errno == EINTR)) continue;
218 goto done;
219 }
220 }
221done:
222 close(fd);
223}
224#endif
225
226static int create_service_thread(void (*func)(int, void *), void *cookie)
227{
228 stinfo *sti;
229 adb_thread_t t;
230 int s[2];
231
232 if(adb_socketpair(s)) {
233 printf("cannot create service socket pair\n");
234 return -1;
235 }
236
237 sti = malloc(sizeof(stinfo));
238 if(sti == 0) fatal("cannot allocate stinfo");
239 sti->func = func;
240 sti->cookie = cookie;
241 sti->fd = s[1];
242
243 if(adb_thread_create( &t, service_bootstrap_func, sti)){
244 free(sti);
245 adb_close(s[0]);
246 adb_close(s[1]);
247 printf("cannot create service thread\n");
248 return -1;
249 }
250
251 D("service thread started, %d:%d\n",s[0], s[1]);
252 return s[0];
253}
254
255static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
256{
Joe Onorato91acb142009-09-03 16:30:43 -0700257#ifdef HAVE_WIN32_PROC
258 fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
259 return -1;
260#else /* !HAVE_WIN32_PROC */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800261 char *devname;
262 int ptm;
263 pid_t pid;
264
265 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
266 if(ptm < 0){
267 printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
268 return -1;
269 }
270 fcntl(ptm, F_SETFD, FD_CLOEXEC);
271
272 if(grantpt(ptm) || unlockpt(ptm) ||
273 ((devname = (char*) ptsname(ptm)) == 0)){
274 printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
275 return -1;
276 }
277
278 pid = fork();
279 if(pid < 0) {
280 printf("- fork failed: %s -\n", strerror(errno));
281 return -1;
282 }
283
284 if(pid == 0){
285 int pts;
286
287 setsid();
288
289 pts = unix_open(devname, O_RDWR);
290 if(pts < 0) exit(-1);
291
292 dup2(pts, 0);
293 dup2(pts, 1);
294 dup2(pts, 2);
295
296 adb_close(ptm);
297
298 execl(cmd, cmd, arg0, arg1, NULL);
299 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
300 cmd, strerror(errno), errno);
301 exit(-1);
302 } else {
Joe Onorato91acb142009-09-03 16:30:43 -0700303#if !ADB_HOST
Mike Lockwood249ad572009-05-20 09:14:30 -0400304 // set child's OOM adjustment to zero
305 char text[64];
306 snprintf(text, sizeof text, "/proc/%d/oom_adj", pid);
307 int fd = adb_open(text, O_WRONLY);
308 if (fd >= 0) {
309 adb_write(fd, "0", 1);
310 adb_close(fd);
311 } else {
312 D("adb: unable to open %s\n", text);
313 }
Joe Onorato91acb142009-09-03 16:30:43 -0700314#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800315 return ptm;
316 }
Joe Onorato91acb142009-09-03 16:30:43 -0700317#endif /* !HAVE_WIN32_PROC */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800318}
319
320#if ADB_HOST
321#define SHELL_COMMAND "/bin/sh"
322#else
323#define SHELL_COMMAND "/system/bin/sh"
324#endif
325
326int service_to_fd(const char *name)
327{
328 int ret = -1;
329
330 if(!strncmp(name, "tcp:", 4)) {
331 int port = atoi(name + 4);
332 name = strchr(name + 4, ':');
333 if(name == 0) {
334 ret = socket_loopback_client(port, SOCK_STREAM);
335 if (ret >= 0)
336 disable_tcp_nagle(ret);
337 } else {
338#if ADB_HOST
339 adb_mutex_lock(&dns_lock);
340 ret = socket_network_client(name + 1, port, SOCK_STREAM);
341 adb_mutex_unlock(&dns_lock);
342#else
343 return -1;
344#endif
345 }
346#ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
347 } else if(!strncmp(name, "local:", 6)) {
348 ret = socket_local_client(name + 6,
349 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
350 } else if(!strncmp(name, "localreserved:", 14)) {
351 ret = socket_local_client(name + 14,
352 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
353 } else if(!strncmp(name, "localabstract:", 14)) {
354 ret = socket_local_client(name + 14,
355 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
356 } else if(!strncmp(name, "localfilesystem:", 16)) {
357 ret = socket_local_client(name + 16,
358 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
359#endif
360#if ADB_HOST
361 } else if(!strncmp("dns:", name, 4)){
362 char *n = strdup(name + 4);
363 if(n == 0) return -1;
364 ret = create_service_thread(dns_service, n);
365#else /* !ADB_HOST */
366 } else if(!strncmp("dev:", name, 4)) {
367 ret = unix_open(name + 4, O_RDWR);
368 } else if(!strncmp(name, "framebuffer:", 12)) {
369 ret = create_service_thread(framebuffer_service, 0);
370 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
371 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
372 } else if (!strncmp(name, "jdwp:", 5)) {
373 ret = create_jdwp_connection_fd(atoi(name+5));
374 } else if (!strncmp(name, "log:", 4)) {
375 ret = create_service_thread(log_service, get_log_file_path(name + 4));
Joe Onorato91acb142009-09-03 16:30:43 -0700376#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800377 } else if(!HOST && !strncmp(name, "shell:", 6)) {
378 if(name[6]) {
Joe Onorato91acb142009-09-03 16:30:43 -0700379 ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800380 } else {
Joe Onorato91acb142009-09-03 16:30:43 -0700381 ret = create_subprocess(SHELL_COMMAND, "-", 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800382 }
Joe Onorato91acb142009-09-03 16:30:43 -0700383#if !ADB_HOST
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800384 } else if(!strncmp(name, "sync:", 5)) {
385 ret = create_service_thread(file_sync_service, NULL);
386 } else if(!strncmp(name, "remount:", 8)) {
387 ret = create_service_thread(remount_service, NULL);
Mike Lockwoodee156622009-08-04 20:37:51 -0400388 } else if(!strncmp(name, "reboot:", 7)) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700389 const char* arg = name + 7;
Mike Lockwoodee156622009-08-04 20:37:51 -0400390 if (*name == 0)
391 arg = NULL;
Mike Lockwoodff196702009-08-24 15:58:40 -0700392 ret = create_service_thread(reboot_service, (void *)arg);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700393 } else if(!strncmp(name, "root:", 5)) {
394 ret = create_service_thread(restart_root_service, NULL);
Mike Lockwoodff196702009-08-24 15:58:40 -0700395 } else if(!strncmp(name, "tcpip:", 6)) {
396 int port;
397 if (sscanf(name + 6, "%d", &port) == 0) {
398 port = 0;
399 }
400 ret = create_service_thread(restart_tcp_service, (void *)port);
401 } else if(!strncmp(name, "usb:", 4)) {
402 ret = create_service_thread(restart_usb_service, NULL);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800403#endif
404#if 0
405 } else if(!strncmp(name, "echo:", 5)){
406 ret = create_service_thread(echo_service, 0);
407#endif
408 }
409 if (ret >= 0) {
410 close_on_exec(ret);
411 }
412 return ret;
413}
414
415#if ADB_HOST
416struct state_info {
417 transport_type transport;
418 char* serial;
419 int state;
420};
421
422static void wait_for_state(int fd, void* cookie)
423{
424 struct state_info* sinfo = cookie;
425 char* err = "unknown error";
426
427 D("wait_for_state %d\n", sinfo->state);
428
429 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
430 if(t != 0) {
431 writex(fd, "OKAY", 4);
432 } else {
433 sendfailmsg(fd, err);
434 }
435
436 if (sinfo->serial)
437 free(sinfo->serial);
438 free(sinfo);
439 adb_close(fd);
440 D("wait_for_state is done\n");
441}
442#endif
443
444#if ADB_HOST
445asocket* host_service_to_socket(const char* name, const char *serial)
446{
447 if (!strcmp(name,"track-devices")) {
448 return create_device_tracker();
449 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
450 struct state_info* sinfo = malloc(sizeof(struct state_info));
451
452 if (serial)
453 sinfo->serial = strdup(serial);
454 else
455 sinfo->serial = NULL;
456
457 name += strlen("wait-for-");
458
459 if (!strncmp(name, "local", strlen("local"))) {
460 sinfo->transport = kTransportLocal;
461 sinfo->state = CS_DEVICE;
462 } else if (!strncmp(name, "usb", strlen("usb"))) {
463 sinfo->transport = kTransportUsb;
464 sinfo->state = CS_DEVICE;
465 } else if (!strncmp(name, "any", strlen("any"))) {
466 sinfo->transport = kTransportAny;
467 sinfo->state = CS_DEVICE;
468 } else {
469 free(sinfo);
470 return NULL;
471 }
472
473 int fd = create_service_thread(wait_for_state, sinfo);
474 return create_local_socket(fd);
475 }
476 return NULL;
477}
478#endif /* ADB_HOST */