blob: 2c959a44157e4e3e21208f50a075e8b26015fe68 [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
Dan Albert33134262015-03-19 15:21:08 -070017#define TRACE_TAG TRACE_ADB
18
19#include "sysdeps.h"
20#include "adb.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021
Dan Albertea2175a2015-03-08 21:12:08 -070022#include <ctype.h>
23#include <errno.h>
24#include <stdarg.h>
25#include <stddef.h>
26#include <stdint.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080027#include <stdio.h>
28#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080029#include <string.h>
Mike Lockwood1f546e62009-05-25 18:17:55 -040030#include <sys/time.h>
Dan Albertea2175a2015-03-08 21:12:08 -070031#include <time.h>
32
33#include <string>
Dan Alberte2462192015-03-19 13:25:27 -070034#include <vector>
35#include <unordered_map>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036
Dan Albert9313c0d2015-05-21 13:58:50 -070037#include <base/logging.h>
Elliott Hughes7b506092015-04-20 08:09:20 -070038#include <base/stringprintf.h>
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -070039#include <base/strings.h>
Elliott Hughes7b506092015-04-20 08:09:20 -070040
Benoit Gobyd5fcafa2012-04-12 12:23:49 -070041#include "adb_auth.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080042#include "adb_io.h"
Dan Alberte9fca142015-02-18 18:03:26 -080043#include "adb_listeners.h"
Dan Albert76649012015-02-24 15:51:19 -080044#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080045
Scott Andersone82c2db2012-05-25 14:10:02 -070046#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
47
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080048#if !ADB_HOST
Nick Kralevich893a4a42013-05-23 09:54:13 -070049#include <cutils/properties.h>
Nick Kraleviche2864bf2013-02-28 14:12:58 -080050#include <sys/capability.h>
Jeff Sharkey885342a2012-08-14 21:00:22 -070051#include <sys/mount.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080052#endif
53
Dan Albert9313c0d2015-05-21 13:58:50 -070054ADB_MUTEX_DEFINE(D_lock);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080055
56int HOST = 0;
57
Scott Andersone82c2db2012-05-25 14:10:02 -070058#if !ADB_HOST
Dan Albert9313c0d2015-05-21 13:58:50 -070059const char* adb_device_banner = "device";
60static android::base::LogdLogger gLogdLogger;
Scott Andersone82c2db2012-05-25 14:10:02 -070061#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080062
Dan Albert9313c0d2015-05-21 13:58:50 -070063void AdbLogger(android::base::LogId id, android::base::LogSeverity severity,
64 const char* tag, const char* file, unsigned int line,
65 const char* message) {
66 android::base::StderrLogger(id, severity, tag, file, line, message);
67#if !ADB_HOST
68 gLogdLogger(id, severity, tag, file, line, message);
69#endif
70}
71
72void fatal(const char *fmt, ...) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080073 va_list ap;
74 va_start(ap, fmt);
75 fprintf(stderr, "error: ");
76 vfprintf(stderr, fmt, ap);
77 fprintf(stderr, "\n");
78 va_end(ap);
79 exit(-1);
80}
81
Dan Albert9313c0d2015-05-21 13:58:50 -070082void fatal_errno(const char* fmt, ...) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080083 va_list ap;
84 va_start(ap, fmt);
85 fprintf(stderr, "error: %s: ", strerror(errno));
86 vfprintf(stderr, fmt, ap);
87 fprintf(stderr, "\n");
88 va_end(ap);
89 exit(-1);
90}
91
Dan Albertea2175a2015-03-08 21:12:08 -070092#if !ADB_HOST
Dan Albert9313c0d2015-05-21 13:58:50 -070093static std::string get_log_file_name() {
Dan Albertea2175a2015-03-08 21:12:08 -070094 struct tm now;
95 time_t t;
96 tzset();
97 time(&t);
98 localtime_r(&t, &now);
99
Dan Albert8743ef92015-03-19 22:53:30 -0700100 char timestamp[PATH_MAX];
101 strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
Dan Albertea2175a2015-03-08 21:12:08 -0700102
Dan Albert9313c0d2015-05-21 13:58:50 -0700103 return android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp,
104 getpid());
105}
106
107void start_device_log(void) {
108 int fd = unix_open(get_log_file_name().c_str(),
109 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
Dan Albertea2175a2015-03-08 21:12:08 -0700110 if (fd == -1) {
111 return;
112 }
113
Dan Albert9313c0d2015-05-21 13:58:50 -0700114 // Redirect stdout and stderr to the log file.
Dan Albertea2175a2015-03-08 21:12:08 -0700115 dup2(fd, STDOUT_FILENO);
116 dup2(fd, STDERR_FILENO);
117 fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
118 adb_close(fd);
Dan Albertea2175a2015-03-08 21:12:08 -0700119}
120#endif
121
122int adb_trace_mask;
123
124std::string get_trace_setting_from_env() {
125 const char* setting = getenv("ADB_TRACE");
126 if (setting == nullptr) {
127 setting = "";
128 }
129
130 return std::string(setting);
131}
132
133#if !ADB_HOST
134std::string get_trace_setting_from_prop() {
135 char buf[PROPERTY_VALUE_MAX];
136 property_get("persist.adb.trace_mask", buf, "");
137 return std::string(buf);
138}
139#endif
140
141std::string get_trace_setting() {
142#if ADB_HOST
143 return get_trace_setting_from_env();
144#else
145 return get_trace_setting_from_prop();
146#endif
147}
148
Dan Alberte2462192015-03-19 13:25:27 -0700149// Split the space separated list of tags from the trace setting and build the
150// trace mask from it. note that '1' and 'all' are special cases to enable all
151// tracing.
Dan Albertea2175a2015-03-08 21:12:08 -0700152//
153// adb's trace setting comes from the ADB_TRACE environment variable, whereas
154// adbd's comes from the system property persist.adb.trace_mask.
Dan Albert9313c0d2015-05-21 13:58:50 -0700155static void setup_trace_mask() {
Dan Albertea2175a2015-03-08 21:12:08 -0700156 const std::string trace_setting = get_trace_setting();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800157
Dan Alberte2462192015-03-19 13:25:27 -0700158 std::unordered_map<std::string, int> trace_flags = {
159 {"1", 0},
160 {"all", 0},
161 {"adb", TRACE_ADB},
162 {"sockets", TRACE_SOCKETS},
163 {"packets", TRACE_PACKETS},
164 {"rwx", TRACE_RWX},
165 {"usb", TRACE_USB},
166 {"sync", TRACE_SYNC},
167 {"sysdeps", TRACE_SYSDEPS},
168 {"transport", TRACE_TRANSPORT},
169 {"jdwp", TRACE_JDWP},
170 {"services", TRACE_SERVICES},
171 {"auth", TRACE_AUTH}};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800172
Dan Alberte2462192015-03-19 13:25:27 -0700173 std::vector<std::string> elements = android::base::Split(trace_setting, " ");
174 for (const auto& elem : elements) {
175 const auto& flag = trace_flags.find(elem);
176 if (flag == trace_flags.end()) {
177 D("Unknown trace flag: %s", flag->first.c_str());
178 continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800179 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800180
Dan Alberte2462192015-03-19 13:25:27 -0700181 if (flag->second == 0) {
182 // 0 is used for the special values "1" and "all" that enable all
183 // tracing.
184 adb_trace_mask = ~0;
185 return;
186 } else {
187 adb_trace_mask |= 1 << flag->second;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800188 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800189 }
Dan Albert9313c0d2015-05-21 13:58:50 -0700190}
Dan Albertea2175a2015-03-08 21:12:08 -0700191
Dan Albert9313c0d2015-05-21 13:58:50 -0700192void adb_trace_init(char** argv) {
Dan Albertea2175a2015-03-08 21:12:08 -0700193#if !ADB_HOST
Dan Albert9313c0d2015-05-21 13:58:50 -0700194 if (isatty(STDOUT_FILENO) == 0) {
195 start_device_log();
196 }
Dan Albertea2175a2015-03-08 21:12:08 -0700197#endif
Dan Albert9313c0d2015-05-21 13:58:50 -0700198
199 setup_trace_mask();
200 android::base::InitLogging(argv, AdbLogger);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800201}
202
Dan Albertbac34742015-02-25 17:51:28 -0800203apacket* get_apacket(void)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800204{
Dan Albertbac34742015-02-25 17:51:28 -0800205 apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket)));
206 if (p == nullptr) {
207 fatal("failed to allocate an apacket");
208 }
209
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800210 memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
211 return p;
212}
213
214void put_apacket(apacket *p)
215{
216 free(p);
217}
218
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700219void handle_online(atransport *t)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800220{
221 D("adb: online\n");
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700222 t->online = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223}
224
225void handle_offline(atransport *t)
226{
227 D("adb: offline\n");
228 //Close the associated usb
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700229 t->online = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800230 run_transport_disconnects(t);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800231}
232
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700233#if DEBUG_PACKETS
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234#define DUMPMAX 32
235void print_packet(const char *label, apacket *p)
236{
237 char *tag;
238 char *x;
239 unsigned count;
240
241 switch(p->msg.command){
242 case A_SYNC: tag = "SYNC"; break;
243 case A_CNXN: tag = "CNXN" ; break;
244 case A_OPEN: tag = "OPEN"; break;
245 case A_OKAY: tag = "OKAY"; break;
246 case A_CLSE: tag = "CLSE"; break;
247 case A_WRTE: tag = "WRTE"; break;
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700248 case A_AUTH: tag = "AUTH"; break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800249 default: tag = "????"; break;
250 }
251
252 fprintf(stderr, "%s: %s %08x %08x %04x \"",
253 label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
254 count = p->msg.data_length;
255 x = (char*) p->data;
256 if(count > DUMPMAX) {
257 count = DUMPMAX;
258 tag = "\n";
259 } else {
260 tag = "\"\n";
261 }
262 while(count-- > 0){
263 if((*x >= ' ') && (*x < 127)) {
264 fputc(*x, stderr);
265 } else {
266 fputc('.', stderr);
267 }
268 x++;
269 }
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700270 fputs(tag, stderr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800271}
272#endif
273
274static void send_ready(unsigned local, unsigned remote, atransport *t)
275{
276 D("Calling send_ready \n");
277 apacket *p = get_apacket();
278 p->msg.command = A_OKAY;
279 p->msg.arg0 = local;
280 p->msg.arg1 = remote;
281 send_packet(p, t);
282}
283
284static void send_close(unsigned local, unsigned remote, atransport *t)
285{
286 D("Calling send_close \n");
287 apacket *p = get_apacket();
288 p->msg.command = A_CLSE;
289 p->msg.arg0 = local;
290 p->msg.arg1 = remote;
291 send_packet(p, t);
292}
293
Scott Andersone82c2db2012-05-25 14:10:02 -0700294static size_t fill_connect_data(char *buf, size_t bufsize)
295{
296#if ADB_HOST
297 return snprintf(buf, bufsize, "host::") + 1;
298#else
299 static const char *cnxn_props[] = {
300 "ro.product.name",
301 "ro.product.model",
302 "ro.product.device",
303 };
304 static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
305 int i;
306 size_t remaining = bufsize;
307 size_t len;
308
309 len = snprintf(buf, remaining, "%s::", adb_device_banner);
310 remaining -= len;
311 buf += len;
312 for (i = 0; i < num_cnxn_props; i++) {
313 char value[PROPERTY_VALUE_MAX];
314 property_get(cnxn_props[i], value, "");
315 len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
316 remaining -= len;
317 buf += len;
318 }
319
320 return bufsize - remaining + 1;
321#endif
322}
323
Dan Albertba3a2512015-02-18 17:47:33 -0800324void send_connect(atransport *t)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800325{
326 D("Calling send_connect \n");
327 apacket *cp = get_apacket();
328 cp->msg.command = A_CNXN;
329 cp->msg.arg0 = A_VERSION;
330 cp->msg.arg1 = MAX_PAYLOAD;
Scott Andersone82c2db2012-05-25 14:10:02 -0700331 cp->msg.data_length = fill_connect_data((char *)cp->data,
332 sizeof(cp->data));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800333 send_packet(cp, t);
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700334}
335
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700336// qual_overwrite is used to overwrite a qualifier string. dst is a
337// pointer to a char pointer. It is assumed that if *dst is non-NULL, it
338// was malloc'ed and needs to freed. *dst will be set to a dup of src.
339// TODO: switch to std::string for these atransport fields instead.
340static void qual_overwrite(char** dst, const std::string& src) {
Scott Andersone82c2db2012-05-25 14:10:02 -0700341 free(*dst);
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700342 *dst = strdup(src.c_str());
Scott Andersone82c2db2012-05-25 14:10:02 -0700343}
344
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700345void parse_banner(const char* banner, atransport* t) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800346 D("parse_banner: %s\n", banner);
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700347
348 // The format is something like:
349 // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
350 std::vector<std::string> pieces = android::base::Split(banner, ":");
351
352 if (pieces.size() > 2) {
353 const std::string& props = pieces[2];
354 for (auto& prop : android::base::Split(props, ";")) {
355 // The list of properties was traditionally ;-terminated rather than ;-separated.
356 if (prop.empty()) continue;
357
358 std::vector<std::string> key_value = android::base::Split(prop, "=");
359 if (key_value.size() != 2) continue;
360
361 const std::string& key = key_value[0];
362 const std::string& value = key_value[1];
363 if (key == "ro.product.name") {
364 qual_overwrite(&t->product, value);
365 } else if (key == "ro.product.model") {
366 qual_overwrite(&t->model, value);
367 } else if (key == "ro.product.device") {
368 qual_overwrite(&t->device, value);
Scott Andersone82c2db2012-05-25 14:10:02 -0700369 }
370 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800371 }
372
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700373 const std::string& type = pieces[0];
374 if (type == "bootloader") {
Dan Albertdcd78a12015-05-18 16:43:57 -0700375 D("setting connection_state to kCsBootloader\n");
376 t->connection_state = kCsBootloader;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800377 update_transports();
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700378 } else if (type == "device") {
Dan Albertdcd78a12015-05-18 16:43:57 -0700379 D("setting connection_state to kCsDevice\n");
380 t->connection_state = kCsDevice;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800381 update_transports();
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700382 } else if (type == "recovery") {
Dan Albertdcd78a12015-05-18 16:43:57 -0700383 D("setting connection_state to kCsRecovery\n");
384 t->connection_state = kCsRecovery;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800385 update_transports();
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700386 } else if (type == "sideload") {
Dan Albertdcd78a12015-05-18 16:43:57 -0700387 D("setting connection_state to kCsSideload\n");
388 t->connection_state = kCsSideload;
Doug Zongker447f0612012-01-09 14:54:53 -0800389 update_transports();
Elliott Hughes3ce95752015-04-29 22:37:25 -0700390 } else {
Dan Albertdcd78a12015-05-18 16:43:57 -0700391 D("setting connection_state to kCsHost\n");
392 t->connection_state = kCsHost;
Doug Zongker447f0612012-01-09 14:54:53 -0800393 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800394}
395
396void handle_packet(apacket *p, atransport *t)
397{
398 asocket *s;
399
Viral Mehta899913f2010-06-16 18:41:28 +0530400 D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
401 ((char*) (&(p->msg.command)))[1],
402 ((char*) (&(p->msg.command)))[2],
403 ((char*) (&(p->msg.command)))[3]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800404 print_packet("recv", p);
405
406 switch(p->msg.command){
407 case A_SYNC:
408 if(p->msg.arg0){
409 send_packet(p, t);
410 if(HOST) send_connect(t);
411 } else {
Dan Albertdcd78a12015-05-18 16:43:57 -0700412 t->connection_state = kCsOffline;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800413 handle_offline(t);
414 send_packet(p, t);
415 }
416 return;
417
418 case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
419 /* XXX verify version, etc */
Dan Albertdcd78a12015-05-18 16:43:57 -0700420 if(t->connection_state != kCsOffline) {
421 t->connection_state = kCsOffline;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800422 handle_offline(t);
423 }
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700424
Elliott Hughes8d5fa6d2015-04-24 23:02:00 -0700425 parse_banner(reinterpret_cast<const char*>(p->data), t);
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700426
427 if (HOST || !auth_enabled) {
428 handle_online(t);
429 if(!HOST) send_connect(t);
430 } else {
431 send_auth_request(t);
432 }
433 break;
434
435 case A_AUTH:
436 if (p->msg.arg0 == ADB_AUTH_TOKEN) {
Dan Albertdcd78a12015-05-18 16:43:57 -0700437 t->connection_state = kCsUnauthorized;
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700438 t->key = adb_auth_nextkey(t->key);
439 if (t->key) {
440 send_auth_response(p->data, p->msg.data_length, t);
441 } else {
442 /* No more private keys to try, send the public key */
443 send_auth_publickey(t);
444 }
445 } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
446 if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
447 adb_auth_verified(t);
448 t->failed_auth_attempts = 0;
449 } else {
450 if (t->failed_auth_attempts++ > 10)
451 adb_sleep_ms(1000);
452 send_auth_request(t);
453 }
454 } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
455 adb_auth_confirm_key(p->data, p->msg.data_length, t);
456 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800457 break;
458
459 case A_OPEN: /* OPEN(local-id, 0, "destination") */
David 'Digit' Turner818d6412013-12-13 14:09:44 +0100460 if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800461 char *name = (char*) p->data;
462 name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
463 s = create_local_service_socket(name);
464 if(s == 0) {
465 send_close(0, p->msg.arg0, t);
466 } else {
467 s->peer = create_remote_socket(p->msg.arg0, t);
468 s->peer->peer = s;
469 send_ready(s->id, s->peer->id, t);
470 s->ready(s);
471 }
472 }
473 break;
474
475 case A_OKAY: /* READY(local-id, remote-id, "") */
David 'Digit' Turner818d6412013-12-13 14:09:44 +0100476 if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
477 if((s = find_local_socket(p->msg.arg1, 0))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800478 if(s->peer == 0) {
David 'Digit' Turner818d6412013-12-13 14:09:44 +0100479 /* On first READY message, create the connection. */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800480 s->peer = create_remote_socket(p->msg.arg0, t);
481 s->peer->peer = s;
David 'Digit' Turner818d6412013-12-13 14:09:44 +0100482 s->ready(s);
483 } else if (s->peer->id == p->msg.arg0) {
484 /* Other READY messages must use the same local-id */
485 s->ready(s);
486 } else {
487 D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
488 p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800489 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800490 }
491 }
492 break;
493
David 'Digit' Turner818d6412013-12-13 14:09:44 +0100494 case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
495 if (t->online && p->msg.arg1 != 0) {
496 if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
497 /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
498 * a failed OPEN only. However, due to a bug in previous ADB
499 * versions, CLOSE(0, remote-id, "") was also used for normal
500 * CLOSE() operations.
501 *
502 * This is bad because it means a compromised adbd could
503 * send packets to close connections between the host and
504 * other devices. To avoid this, only allow this if the local
505 * socket has a peer on the same transport.
506 */
507 if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
508 D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
509 p->msg.arg1, t->serial, s->peer->transport->serial);
510 } else {
511 s->close(s);
512 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800513 }
514 }
515 break;
516
David 'Digit' Turner818d6412013-12-13 14:09:44 +0100517 case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
518 if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
519 if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800520 unsigned rid = p->msg.arg0;
521 p->len = p->msg.data_length;
522
523 if(s->enqueue(s, p) == 0) {
524 D("Enqueue the socket\n");
525 send_ready(s->id, rid, t);
526 }
527 return;
528 }
529 }
530 break;
531
532 default:
533 printf("handle_packet: what is %08x?!\n", p->msg.command);
534 }
535
536 put_apacket(p);
537}
538
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800539#if ADB_HOST
JP Abgrall571c1362012-12-06 18:18:12 -0800540
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100541int launch_server(int server_port)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800542{
Yabin Cuie77b6a02014-11-11 09:24:11 -0800543#if defined(_WIN32)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800544 /* we need to start the server in the background */
545 /* we create a PIPE that will be used to wait for the server's "OK" */
546 /* message since the pipe handles must be inheritable, we use a */
547 /* security attribute */
548 HANDLE pipe_read, pipe_write;
Ray Donnelly267aa8b2012-11-29 01:18:50 +0000549 HANDLE stdout_handle, stderr_handle;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800550 SECURITY_ATTRIBUTES sa;
551 STARTUPINFO startup;
552 PROCESS_INFORMATION pinfo;
553 char program_path[ MAX_PATH ];
554 int ret;
555
556 sa.nLength = sizeof(sa);
557 sa.lpSecurityDescriptor = NULL;
558 sa.bInheritHandle = TRUE;
559
560 /* create pipe, and ensure its read handle isn't inheritable */
561 ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
562 if (!ret) {
563 fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
564 return -1;
565 }
566
567 SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
568
Ray Donnelly267aa8b2012-11-29 01:18:50 +0000569 /* Some programs want to launch an adb command and collect its output by
570 * calling CreateProcess with inheritable stdout/stderr handles, then
571 * using read() to get its output. When this happens, the stdout/stderr
572 * handles passed to the adb client process will also be inheritable.
573 * When starting the adb server here, care must be taken to reset them
574 * to non-inheritable.
575 * Otherwise, something bad happens: even if the adb command completes,
576 * the calling process is stuck while read()-ing from the stdout/stderr
577 * descriptors, because they're connected to corresponding handles in the
578 * adb server process (even if the latter never uses/writes to them).
579 */
580 stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
581 stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
582 if (stdout_handle != INVALID_HANDLE_VALUE) {
583 SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
584 }
585 if (stderr_handle != INVALID_HANDLE_VALUE) {
586 SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
587 }
588
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800589 ZeroMemory( &startup, sizeof(startup) );
590 startup.cb = sizeof(startup);
591 startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
592 startup.hStdOutput = pipe_write;
593 startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
594 startup.dwFlags = STARTF_USESTDHANDLES;
595
596 ZeroMemory( &pinfo, sizeof(pinfo) );
597
598 /* get path of current program */
599 GetModuleFileName( NULL, program_path, sizeof(program_path) );
Wenhao Lia09558c2013-11-13 16:23:37 +0800600 char args[64];
601 snprintf(args, sizeof(args), "adb -P %d fork-server server", server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800602 ret = CreateProcess(
603 program_path, /* program path */
Wenhao Lia09558c2013-11-13 16:23:37 +0800604 args,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800605 /* the fork-server argument will set the
606 debug = 2 in the child */
607 NULL, /* process handle is not inheritable */
608 NULL, /* thread handle is not inheritable */
609 TRUE, /* yes, inherit some handles */
610 DETACHED_PROCESS, /* the new process doesn't have a console */
611 NULL, /* use parent's environment block */
612 NULL, /* use parent's starting directory */
613 &startup, /* startup info, i.e. std handles */
614 &pinfo );
615
616 CloseHandle( pipe_write );
617
618 if (!ret) {
619 fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
620 CloseHandle( pipe_read );
621 return -1;
622 }
623
624 CloseHandle( pinfo.hProcess );
625 CloseHandle( pinfo.hThread );
626
627 /* wait for the "OK\n" message */
628 {
629 char temp[3];
630 DWORD count;
631
632 ret = ReadFile( pipe_read, temp, 3, &count, NULL );
633 CloseHandle( pipe_read );
634 if ( !ret ) {
635 fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
636 return -1;
637 }
638 if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
639 fprintf(stderr, "ADB server didn't ACK\n" );
640 return -1;
641 }
642 }
Yabin Cuie77b6a02014-11-11 09:24:11 -0800643#else /* !defined(_WIN32) */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800644 char path[PATH_MAX];
645 int fd[2];
646
647 // set up a pipe so the child can tell us when it is ready.
648 // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
649 if (pipe(fd)) {
650 fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
651 return -1;
652 }
Alexey Tarasov31664102009-10-22 02:55:00 +1100653 get_my_path(path, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800654 pid_t pid = fork();
655 if(pid < 0) return -1;
656
657 if (pid == 0) {
658 // child side of the fork
659
660 // redirect stderr to the pipe
661 // we use stderr instead of stdout due to stdout's buffering behavior.
662 adb_close(fd[0]);
663 dup2(fd[1], STDERR_FILENO);
664 adb_close(fd[1]);
665
Matt Gumbeld7b33082012-11-14 10:16:17 -0800666 char str_port[30];
667 snprintf(str_port, sizeof(str_port), "%d", server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800668 // child process
Matt Gumbeld7b33082012-11-14 10:16:17 -0800669 int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800670 // this should not return
671 fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
672 } else {
673 // parent side of the fork
674
675 char temp[3];
676
677 temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
678 // wait for the "OK\n" message
679 adb_close(fd[1]);
680 int ret = adb_read(fd[0], temp, 3);
JP Abgrall408fa572011-03-16 15:57:42 -0700681 int saved_errno = errno;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800682 adb_close(fd[0]);
683 if (ret < 0) {
JP Abgrall408fa572011-03-16 15:57:42 -0700684 fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800685 return -1;
686 }
687 if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
688 fprintf(stderr, "ADB server didn't ACK\n" );
689 return -1;
690 }
691
692 setsid();
693 }
Yabin Cuie77b6a02014-11-11 09:24:11 -0800694#endif /* !defined(_WIN32) */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800695 return 0;
696}
Yabin Cuie77b6a02014-11-11 09:24:11 -0800697#endif /* ADB_HOST */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800698
David 'Digit' Turner25258692013-03-21 21:07:42 +0100699// Try to handle a network forwarding request.
700// This returns 1 on success, 0 on failure, and -1 to indicate this is not
701// a forwarding-related request.
Elliott Hughesaee80fb2015-05-07 21:38:41 -0700702int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd)
David 'Digit' Turner25258692013-03-21 21:07:42 +0100703{
704 if (!strcmp(service, "list-forward")) {
705 // Create the list of forward redirections.
Elliott Hughese67f1f82015-04-30 17:32:03 -0700706 std::string listeners = format_listeners();
David 'Digit' Turner25258692013-03-21 21:07:42 +0100707#if ADB_HOST
Elliott Hughese67f1f82015-04-30 17:32:03 -0700708 SendOkay(reply_fd);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100709#endif
Elliott Hughese67f1f82015-04-30 17:32:03 -0700710 SendProtocolString(reply_fd, listeners);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100711 return 1;
712 }
713
714 if (!strcmp(service, "killforward-all")) {
715 remove_all_listeners();
716#if ADB_HOST
717 /* On the host: 1st OKAY is connect, 2nd OKAY is status */
Elliott Hughese67f1f82015-04-30 17:32:03 -0700718 SendOkay(reply_fd);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100719#endif
Elliott Hughese67f1f82015-04-30 17:32:03 -0700720 SendOkay(reply_fd);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100721 return 1;
722 }
723
724 if (!strncmp(service, "forward:",8) ||
725 !strncmp(service, "killforward:",12)) {
Dan Albertbac34742015-02-25 17:51:28 -0800726 char *local, *remote;
David 'Digit' Turner25258692013-03-21 21:07:42 +0100727 atransport *transport;
728
729 int createForward = strncmp(service, "kill", 4);
730 int no_rebind = 0;
731
732 local = strchr(service, ':') + 1;
733
734 // Handle forward:norebind:<local>... here
735 if (createForward && !strncmp(local, "norebind:", 9)) {
736 no_rebind = 1;
737 local = strchr(local, ':') + 1;
738 }
739
740 remote = strchr(local,';');
741
742 if (createForward) {
743 // Check forward: parameter format: '<local>;<remote>'
744 if(remote == 0) {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700745 SendFail(reply_fd, "malformed forward spec");
David 'Digit' Turner25258692013-03-21 21:07:42 +0100746 return 1;
747 }
748
749 *remote++ = 0;
750 if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700751 SendFail(reply_fd, "malformed forward spec");
David 'Digit' Turner25258692013-03-21 21:07:42 +0100752 return 1;
753 }
754 } else {
755 // Check killforward: parameter format: '<local>'
756 if (local[0] == 0) {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700757 SendFail(reply_fd, "malformed forward spec");
David 'Digit' Turner25258692013-03-21 21:07:42 +0100758 return 1;
759 }
760 }
761
Elliott Hughes7be29c82015-04-16 22:54:44 -0700762 std::string error_msg;
Dan Albertdcd78a12015-05-18 16:43:57 -0700763 transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100764 if (!transport) {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700765 SendFail(reply_fd, error_msg);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100766 return 1;
767 }
768
Elliott Hughes3bd73c12015-05-05 13:10:43 -0700769 InstallStatus r;
David 'Digit' Turner25258692013-03-21 21:07:42 +0100770 if (createForward) {
771 r = install_listener(local, remote, transport, no_rebind);
772 } else {
773 r = remove_listener(local, transport);
774 }
Elliott Hughes7b506092015-04-20 08:09:20 -0700775 if (r == INSTALL_STATUS_OK) {
David 'Digit' Turner25258692013-03-21 21:07:42 +0100776#if ADB_HOST
777 /* On the host: 1st OKAY is connect, 2nd OKAY is status */
Elliott Hughese67f1f82015-04-30 17:32:03 -0700778 SendOkay(reply_fd);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100779#endif
Elliott Hughese67f1f82015-04-30 17:32:03 -0700780 SendOkay(reply_fd);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100781 return 1;
782 }
783
Elliott Hughes7b506092015-04-20 08:09:20 -0700784 std::string message;
785 switch (r) {
786 case INSTALL_STATUS_OK: message = " "; break;
787 case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
788 case INSTALL_STATUS_CANNOT_BIND:
789 message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
790 break;
791 case INSTALL_STATUS_CANNOT_REBIND:
792 message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
793 break;
794 case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
David 'Digit' Turner25258692013-03-21 21:07:42 +0100795 }
Elliott Hughese67f1f82015-04-30 17:32:03 -0700796 SendFail(reply_fd, message);
David 'Digit' Turner25258692013-03-21 21:07:42 +0100797 return 1;
798 }
799 return 0;
800}
801
Dan Albertc89e0cc2015-05-08 16:13:53 -0700802int handle_host_request(const char* service, TransportType type,
803 const char* serial, int reply_fd, asocket* s) {
804 if (strcmp(service, "kill") == 0) {
805 fprintf(stderr, "adb server killed by remote request\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800806 fflush(stdout);
Elliott Hughese67f1f82015-04-30 17:32:03 -0700807 SendOkay(reply_fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800808 exit(0);
809 }
810
811#if ADB_HOST
Chih-Hung Hsiehf787b382014-09-05 15:38:15 -0700812 atransport *transport = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800813 // "transport:" is used for switching transport with a specified serial number
814 // "transport-usb:" is used for switching transport to the only USB transport
815 // "transport-local:" is used for switching transport to the only local transport
816 // "transport-any:" is used for switching transport to the only transport
817 if (!strncmp(service, "transport", strlen("transport"))) {
Elliott Hughes3bd73c12015-05-05 13:10:43 -0700818 TransportType type = kTransportAny;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800819
820 if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
821 type = kTransportUsb;
822 } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
823 type = kTransportLocal;
824 } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
825 type = kTransportAny;
826 } else if (!strncmp(service, "transport:", strlen("transport:"))) {
827 service += strlen("transport:");
Tom Marlin3175c8e2011-07-27 12:56:14 -0500828 serial = service;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800829 }
830
Elliott Hughes7be29c82015-04-16 22:54:44 -0700831 std::string error_msg = "unknown failure";
Dan Albertdcd78a12015-05-18 16:43:57 -0700832 transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800833
834 if (transport) {
835 s->transport = transport;
Elliott Hughese67f1f82015-04-30 17:32:03 -0700836 SendOkay(reply_fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800837 } else {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700838 SendFail(reply_fd, error_msg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800839 }
840 return 1;
841 }
842
843 // return a list of all connected devices
Scott Andersone109d262012-04-20 11:21:14 -0700844 if (!strncmp(service, "devices", 7)) {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700845 bool long_listing = (strcmp(service+7, "-l") == 0);
846 if (long_listing || service[7] == 0) {
847 D("Getting device list...\n");
848 std::string device_list = list_transports(long_listing);
849 D("Sending device list...\n");
850 SendOkay(reply_fd);
851 SendProtocolString(reply_fd, device_list);
Scott Andersone109d262012-04-20 11:21:14 -0700852 return 0;
853 }
Elliott Hughese67f1f82015-04-30 17:32:03 -0700854 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800855 }
856
Mike Lockwood74d7ff82009-10-11 23:04:18 -0400857 // remove TCP transport
858 if (!strncmp(service, "disconnect:", 11)) {
859 char buffer[4096];
860 memset(buffer, 0, sizeof(buffer));
Elliott Hughesaee80fb2015-05-07 21:38:41 -0700861 const char* serial = service + 11;
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400862 if (serial[0] == 0) {
863 // disconnect from all TCP devices
864 unregister_all_tcp_transports();
Mike Lockwood74d7ff82009-10-11 23:04:18 -0400865 } else {
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400866 char hostbuf[100];
867 // assume port 5555 if no port is specified
868 if (!strchr(serial, ':')) {
869 snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
870 serial = hostbuf;
871 }
872 atransport *t = find_transport(serial);
873
874 if (t) {
875 unregister_transport(t);
876 } else {
877 snprintf(buffer, sizeof(buffer), "No such device %s", serial);
878 }
Mike Lockwood74d7ff82009-10-11 23:04:18 -0400879 }
880
Elliott Hughese67f1f82015-04-30 17:32:03 -0700881 SendOkay(reply_fd);
882 SendProtocolString(reply_fd, buffer);
Mike Lockwood2f38b692009-08-24 15:58:40 -0700883 return 0;
884 }
885
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800886 // returns our value for ADB_SERVER_VERSION
887 if (!strcmp(service, "version")) {
Elliott Hughese67f1f82015-04-30 17:32:03 -0700888 SendOkay(reply_fd);
889 SendProtocolString(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800890 return 0;
891 }
892
893 if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
Dan Albertbac34742015-02-25 17:51:28 -0800894 const char *out = "unknown";
Dan Albertdcd78a12015-05-18 16:43:57 -0700895 transport = acquire_one_transport(kCsAny, type, serial, NULL);
Elliott Hughes7be29c82015-04-16 22:54:44 -0700896 if (transport && transport->serial) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800897 out = transport->serial;
898 }
Elliott Hughese67f1f82015-04-30 17:32:03 -0700899 SendOkay(reply_fd);
900 SendProtocolString(reply_fd, out);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800901 return 0;
902 }
Scott Andersone109d262012-04-20 11:21:14 -0700903 if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
Dan Albertbac34742015-02-25 17:51:28 -0800904 const char *out = "unknown";
Dan Albertdcd78a12015-05-18 16:43:57 -0700905 transport = acquire_one_transport(kCsAny, type, serial, NULL);
Elliott Hughes7be29c82015-04-16 22:54:44 -0700906 if (transport && transport->devpath) {
Scott Andersone109d262012-04-20 11:21:14 -0700907 out = transport->devpath;
908 }
Elliott Hughese67f1f82015-04-30 17:32:03 -0700909 SendOkay(reply_fd);
910 SendProtocolString(reply_fd, out);
Scott Andersone109d262012-04-20 11:21:14 -0700911 return 0;
912 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800913 // indicates a new emulator instance has started
914 if (!strncmp(service,"emulator:",9)) {
915 int port = atoi(service+9);
916 local_connect(port);
917 /* we don't even need to send a reply */
918 return 0;
919 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800920
921 if(!strncmp(service,"get-state",strlen("get-state"))) {
Dan Albertdcd78a12015-05-18 16:43:57 -0700922 transport = acquire_one_transport(kCsAny, type, serial, NULL);
Elliott Hughese67f1f82015-04-30 17:32:03 -0700923 SendOkay(reply_fd);
924 SendProtocolString(reply_fd, transport->connection_state_name());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800925 return 0;
926 }
Simon Yedc22c3c2014-07-14 17:23:06 -0700927#endif // ADB_HOST
928
Elliott Hughes3bd73c12015-05-05 13:10:43 -0700929 int ret = handle_forward_request(service, type, serial, reply_fd);
Simon Yedc22c3c2014-07-14 17:23:06 -0700930 if (ret >= 0)
931 return ret - 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800932 return -1;
933}