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