Merge "support "sideload over ADB" mode"

This commit is contained in:
Doug Zongker
2012-01-10 10:19:00 -08:00
committed by Android (Google) Code Review
22 changed files with 5704 additions and 9 deletions
+4 -2
View File
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := \
roots.cpp \
ui.cpp \
screen_ui.cpp \
verifier.cpp
verifier.cpp \
adb_install.cpp
LOCAL_MODULE := recovery
@@ -40,7 +41,7 @@ else
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
endif
LOCAL_STATIC_LIBRARIES += libext4_utils libz
LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt
LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt libminadbd
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
LOCAL_STATIC_LIBRARIES += libstdc++ libc
@@ -67,6 +68,7 @@ include $(BUILD_EXECUTABLE)
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minelf/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/minadbd/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
include $(commands_recovery_local_path)/tools/Android.mk
include $(commands_recovery_local_path)/edify/Android.mk
+110
View File
@@ -0,0 +1,110 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include "ui.h"
#include "cutils/properties.h"
#include "install.h"
#include "common.h"
#include "adb_install.h"
extern "C" {
#include "minadbd/adb.h"
}
static RecoveryUI* ui = NULL;
static void
set_usb_driver(bool enabled) {
int fd = open("/sys/class/android_usb/android0/enable", O_WRONLY);
if (fd < 0) {
ui->Print("failed to open driver control: %s\n", strerror(errno));
return;
}
if (write(fd, enabled ? "1" : "0", 1) < 0) {
ui->Print("failed to set driver control: %s\n", strerror(errno));
}
if (close(fd) < 0) {
ui->Print("failed to close driver control: %s\n", strerror(errno));
}
}
static void
stop_adbd() {
property_set("ctl.stop", "adbd");
set_usb_driver(false);
}
static void
maybe_restart_adbd() {
char value[PROPERTY_VALUE_MAX+1];
int len = property_get("ro.debuggable", value, NULL);
if (len == 1 && value[0] == '1') {
ui->Print("Restarting adbd...\n");
set_usb_driver(true);
property_set("ctl.start", "adbd");
}
}
int
apply_from_adb(RecoveryUI* ui_, int* wipe_cache, const char* install_file) {
ui = ui_;
stop_adbd();
set_usb_driver(true);
ui->Print("\n\nNow send the package you want to apply\n"
"to the device with \"adb sideload <filename>\"...\n");
pid_t child;
if ((child = fork()) == 0) {
execl("/sbin/recovery", "recovery", "--adbd", NULL);
_exit(-1);
}
int status;
// TODO(dougz): there should be a way to cancel waiting for a
// package (by pushing some button combo on the device). For now
// you just have to 'adb sideload' a file that's not a valid
// package, like "/dev/null".
waitpid(child, &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
ui->Print("status %d\n", WEXITSTATUS(status));
}
set_usb_driver(false);
maybe_restart_adbd();
struct stat st;
if (stat(ADB_SIDELOAD_FILENAME, &st) != 0) {
if (errno == ENOENT) {
ui->Print("No package received.\n");
} else {
ui->Print("Error reading package:\n %s\n", strerror(errno));
}
return INSTALL_ERROR;
}
return install_package(ADB_SIDELOAD_FILENAME, wipe_cache, install_file);
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _ADB_INSTALL_H
#define _ADB_INSTALL_H
class RecoveryUI;
int apply_from_adb(RecoveryUI* h, int* wipe_cache, const char* install_file);
#endif
+4 -6
View File
@@ -26,8 +26,7 @@ static const char* HEADERS[] = { "Volume up/down to move highlight;",
NULL };
static const char* ITEMS[] = {"reboot system now",
"apply update from external storage",
"apply update from cache",
"apply update from ADB",
"wipe data/factory reset",
"wipe cache partition",
NULL };
@@ -72,10 +71,9 @@ class DefaultDevice : public Device {
BuiltinAction InvokeMenuItem(int menu_position) {
switch (menu_position) {
case 0: return REBOOT;
case 1: return APPLY_EXT;
case 2: return APPLY_CACHE;
case 3: return WIPE_DATA;
case 4: return WIPE_CACHE;
case 1: return APPLY_ADB_SIDELOAD;
case 2: return WIPE_DATA;
case 3: return WIPE_CACHE;
default: return NO_ACTION;
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ class Device {
virtual int HandleMenuKey(int key, int visible) = 0;
enum BuiltinAction { NO_ACTION, REBOOT, APPLY_EXT, APPLY_CACHE,
WIPE_DATA, WIPE_CACHE };
APPLY_ADB_SIDELOAD, WIPE_DATA, WIPE_CACHE };
// Perform a recovery action selected from the menu.
// 'menu_position' will be the item number of the selected menu
+32
View File
@@ -0,0 +1,32 @@
# Copyright 2005 The Android Open Source Project
#
# Android.mk for adb
#
LOCAL_PATH:= $(call my-dir)
# minadbd library
# =========================================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
adb.c \
fdevent.c \
transport.c \
transport_usb.c \
sockets.c \
services.c \
usb_linux_client.c \
utils.c
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE := libminadbd
LOCAL_STATIC_LIBRARIES := libcutils libc
include $(BUILD_STATIC_LIBRARY)
+27
View File
@@ -0,0 +1,27 @@
The contents of this directory are copied from system/core/adb, with
the following changes:
adb.c
- much support for host mode and non-linux OS's stripped out; this
version only runs as adbd on the device.
- does not setuid/setgid itself (always stays root)
- only uses USB transport
- references to JDWP removed
- main() removed
adb.h
- minor changes to match adb.c changes
sockets.c
- references to JDWP removed
services.c
- all services except echo_service (which is commented out) removed
- all host mode support removed
- sideload_service() added; this is the only service supported. It
receives a single blob of data, writes it to a fixed filename, and
makes the process exit.
Android.mk
- only builds in adbd mode; builds as static library instead of a
standalone executable.
+1151
View File
File diff suppressed because it is too large Load Diff
+443
View File
@@ -0,0 +1,443 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __ADB_H
#define __ADB_H
#include <limits.h>
#include "transport.h" /* readx(), writex() */
#include "fdevent.h"
#define MAX_PAYLOAD 4096
#define A_SYNC 0x434e5953
#define A_CNXN 0x4e584e43
#define A_OPEN 0x4e45504f
#define A_OKAY 0x59414b4f
#define A_CLSE 0x45534c43
#define A_WRTE 0x45545257
#define A_VERSION 0x01000000 // ADB protocol version
#define ADB_VERSION_MAJOR 1 // Used for help/version information
#define ADB_VERSION_MINOR 0 // Used for help/version information
#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server
typedef struct amessage amessage;
typedef struct apacket apacket;
typedef struct asocket asocket;
typedef struct alistener alistener;
typedef struct aservice aservice;
typedef struct atransport atransport;
typedef struct adisconnect adisconnect;
typedef struct usb_handle usb_handle;
struct amessage {
unsigned command; /* command identifier constant */
unsigned arg0; /* first argument */
unsigned arg1; /* second argument */
unsigned data_length; /* length of payload (0 is allowed) */
unsigned data_check; /* checksum of data payload */
unsigned magic; /* command ^ 0xffffffff */
};
struct apacket
{
apacket *next;
unsigned len;
unsigned char *ptr;
amessage msg;
unsigned char data[MAX_PAYLOAD];
};
/* An asocket represents one half of a connection between a local and
** remote entity. A local asocket is bound to a file descriptor. A
** remote asocket is bound to the protocol engine.
*/
struct asocket {
/* chain pointers for the local/remote list of
** asockets that this asocket lives in
*/
asocket *next;
asocket *prev;
/* the unique identifier for this asocket
*/
unsigned id;
/* flag: set when the socket's peer has closed
** but packets are still queued for delivery
*/
int closing;
/* the asocket we are connected to
*/
asocket *peer;
/* For local asockets, the fde is used to bind
** us to our fd event system. For remote asockets
** these fields are not used.
*/
fdevent fde;
int fd;
/* queue of apackets waiting to be written
*/
apacket *pkt_first;
apacket *pkt_last;
/* enqueue is called by our peer when it has data
** for us. It should return 0 if we can accept more
** data or 1 if not. If we return 1, we must call
** peer->ready() when we once again are ready to
** receive data.
*/
int (*enqueue)(asocket *s, apacket *pkt);
/* ready is called by the peer when it is ready for
** us to send data via enqueue again
*/
void (*ready)(asocket *s);
/* close is called by the peer when it has gone away.
** we are not allowed to make any further calls on the
** peer once our close method is called.
*/
void (*close)(asocket *s);
/* socket-type-specific extradata */
void *extra;
/* A socket is bound to atransport */
atransport *transport;
};
/* the adisconnect structure is used to record a callback that
** will be called whenever a transport is disconnected (e.g. by the user)
** this should be used to cleanup objects that depend on the
** transport (e.g. remote sockets, listeners, etc...)
*/
struct adisconnect
{
void (*func)(void* opaque, atransport* t);
void* opaque;
adisconnect* next;
adisconnect* prev;
};
/* a transport object models the connection to a remote device or emulator
** there is one transport per connected device/emulator. a "local transport"
** connects through TCP (for the emulator), while a "usb transport" through
** USB (for real devices)
**
** note that kTransportHost doesn't really correspond to a real transport
** object, it's a special value used to indicate that a client wants to
** connect to a service implemented within the ADB server itself.
*/
typedef enum transport_type {
kTransportUsb,
kTransportLocal,
kTransportAny,
kTransportHost,
} transport_type;
struct atransport
{
atransport *next;
atransport *prev;
int (*read_from_remote)(apacket *p, atransport *t);
int (*write_to_remote)(apacket *p, atransport *t);
void (*close)(atransport *t);
void (*kick)(atransport *t);
int fd;
int transport_socket;
fdevent transport_fde;
int ref_count;
unsigned sync_token;
int connection_state;
transport_type type;
/* usb handle or socket fd as needed */
usb_handle *usb;
int sfd;
/* used to identify transports for clients */
char *serial;
char *product;
int adb_port; // Use for emulators (local transport)
/* a list of adisconnect callbacks called when the transport is kicked */
int kicked;
adisconnect disconnects;
};
/* A listener is an entity which binds to a local port
** and, upon receiving a connection on that port, creates
** an asocket to connect the new local connection to a
** specific remote service.
**
** TODO: some listeners read from the new connection to
** determine what exact service to connect to on the far
** side.
*/
struct alistener
{
alistener *next;
alistener *prev;
fdevent fde;
int fd;
const char *local_name;
const char *connect_to;
atransport *transport;
adisconnect disconnect;
};
void print_packet(const char *label, apacket *p);
asocket *find_local_socket(unsigned id);
void install_local_socket(asocket *s);
void remove_socket(asocket *s);
void close_all_sockets(atransport *t);
#define LOCAL_CLIENT_PREFIX "emulator-"
asocket *create_local_socket(int fd);
asocket *create_local_service_socket(const char *destination);
asocket *create_remote_socket(unsigned id, atransport *t);
void connect_to_remote(asocket *s, const char *destination);
void connect_to_smartsocket(asocket *s);
void fatal(const char *fmt, ...);
void fatal_errno(const char *fmt, ...);
void handle_packet(apacket *p, atransport *t);
void send_packet(apacket *p, atransport *t);
void get_my_path(char *s, size_t maxLen);
int launch_server(int server_port);
int adb_main();
/* transports are ref-counted
** get_device_transport does an acquire on your behalf before returning
*/
void init_transport_registration(void);
int list_transports(char *buf, size_t bufsize);
void update_transports(void);
asocket* create_device_tracker(void);
/* Obtain a transport from the available transports.
** If state is != CS_ANY, only transports in that state are considered.
** If serial is non-NULL then only the device with that serial will be chosen.
** If no suitable transport is found, error is set.
*/
atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
void add_transport_disconnect( atransport* t, adisconnect* dis );
void remove_transport_disconnect( atransport* t, adisconnect* dis );
void run_transport_disconnects( atransport* t );
void kick_transport( atransport* t );
/* initialize a transport object's func pointers and state */
#if ADB_HOST
int get_available_local_transport_index();
#endif
int init_socket_transport(atransport *t, int s, int port, int local);
void init_usb_transport(atransport *t, usb_handle *usb, int state);
/* for MacOS X cleanup */
void close_usb_devices();
/* cause new transports to be init'd and added to the list */
void register_socket_transport(int s, const char *serial, int port, int local);
/* these should only be used for the "adb disconnect" command */
void unregister_transport(atransport *t);
void unregister_all_tcp_transports();
void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
/* this should only be used for transports with connection_state == CS_NOPERM */
void unregister_usb_transport(usb_handle *usb);
atransport *find_transport(const char *serial);
#if ADB_HOST
atransport* find_emulator_transport_by_adb_port(int adb_port);
#endif
int service_to_fd(const char *name);
#if ADB_HOST
asocket *host_service_to_socket(const char* name, const char *serial);
#endif
#if !ADB_HOST
typedef enum {
BACKUP,
RESTORE
} BackupOperation;
int backup_service(BackupOperation operation, char* args);
void framebuffer_service(int fd, void *cookie);
void log_service(int fd, void *cookie);
void remount_service(int fd, void *cookie);
char * get_log_file_path(const char * log_name);
#endif
/* packet allocator */
apacket *get_apacket(void);
void put_apacket(apacket *p);
int check_header(apacket *p);
int check_data(apacket *p);
/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
#define ADB_TRACE 1
/* IMPORTANT: if you change the following list, don't
* forget to update the corresponding 'tags' table in
* the adb_trace_init() function implemented in adb.c
*/
typedef enum {
TRACE_ADB = 0, /* 0x001 */
TRACE_SOCKETS,
TRACE_PACKETS,
TRACE_TRANSPORT,
TRACE_RWX, /* 0x010 */
TRACE_USB,
TRACE_SYNC,
TRACE_SYSDEPS,
TRACE_JDWP, /* 0x100 */
TRACE_SERVICES,
} AdbTrace;
#if ADB_TRACE
extern int adb_trace_mask;
extern unsigned char adb_trace_output_count;
void adb_trace_init(void);
# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
/* you must define TRACE_TAG before using this macro */
# define D(...) \
do { \
if (ADB_TRACING) { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
fprintf(stderr, "%s::%s():", \
__FILE__, __FUNCTION__); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} \
} while (0)
# define DR(...) \
do { \
if (ADB_TRACING) { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} \
} while (0)
#else
# define D(...) ((void)0)
# define DR(...) ((void)0)
# define ADB_TRACING 0
#endif
#if !TRACE_PACKETS
#define print_packet(tag,p) do {} while (0)
#endif
#if ADB_HOST_ON_TARGET
/* adb and adbd are coexisting on the target, so use 5038 for adb
* to avoid conflicting with adbd's usage of 5037
*/
# define DEFAULT_ADB_PORT 5038
#else
# define DEFAULT_ADB_PORT 5037
#endif
#define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
#define ADB_CLASS 0xff
#define ADB_SUBCLASS 0x42
#define ADB_PROTOCOL 0x1
void local_init(int port);
int local_connect(int port);
int local_connect_arbitrary_ports(int console_port, int adb_port);
/* usb host/client interface */
void usb_init();
void usb_cleanup();
int usb_write(usb_handle *h, const void *data, int len);
int usb_read(usb_handle *h, void *data, int len);
int usb_close(usb_handle *h);
void usb_kick(usb_handle *h);
/* used for USB device detection */
#if ADB_HOST
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
#endif
unsigned host_to_le32(unsigned n);
int adb_commandline(int argc, char **argv);
int connection_state(atransport *t);
#define CS_ANY -1
#define CS_OFFLINE 0
#define CS_BOOTLOADER 1
#define CS_DEVICE 2
#define CS_HOST 3
#define CS_RECOVERY 4
#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
#define CS_SIDELOAD 6
extern int HOST;
extern int SHELL_EXIT_NOTIFY_FD;
#define CHUNK_SIZE (64*1024)
int sendfailmsg(int fd, const char *reason);
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
#define ADB_SIDELOAD_FILENAME "/tmp/update.zip"
#endif
+695
View File
@@ -0,0 +1,695 @@
/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
**
** Copyright 2006, Brian Swetland <swetland@frotz.net>
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
#include "fdevent.h"
#include "transport.h"
#include "sysdeps.h"
/* !!! Do not enable DEBUG for the adb that will run as the server:
** both stdout and stderr are used to communicate between the client
** and server. Any extra output will cause failures.
*/
#define DEBUG 0 /* non-0 will break adb server */
// This socket is used when a subproc shell service exists.
// It wakes up the fdevent_loop() and cause the correct handling
// of the shell's pseudo-tty master. I.e. force close it.
int SHELL_EXIT_NOTIFY_FD = -1;
static void fatal(const char *fn, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:", fn);
vfprintf(stderr, fmt, ap);
va_end(ap);
abort();
}
#define FATAL(x...) fatal(__FUNCTION__, x)
#if DEBUG
#define D(...) \
do { \
adb_mutex_lock(&D_lock); \
int save_errno = errno; \
fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} while(0)
static void dump_fde(fdevent *fde, const char *info)
{
adb_mutex_lock(&D_lock);
fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
fde->state & FDE_READ ? 'R' : ' ',
fde->state & FDE_WRITE ? 'W' : ' ',
fde->state & FDE_ERROR ? 'E' : ' ',
info);
adb_mutex_unlock(&D_lock);
}
#else
#define D(...) ((void)0)
#define dump_fde(fde, info) do { } while(0)
#endif
#define FDE_EVENTMASK 0x00ff
#define FDE_STATEMASK 0xff00
#define FDE_ACTIVE 0x0100
#define FDE_PENDING 0x0200
#define FDE_CREATED 0x0400
static void fdevent_plist_enqueue(fdevent *node);
static void fdevent_plist_remove(fdevent *node);
static fdevent *fdevent_plist_dequeue(void);
static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
static fdevent list_pending = {
.next = &list_pending,
.prev = &list_pending,
};
static fdevent **fd_table = 0;
static int fd_table_max = 0;
#ifdef CRAPTASTIC
//HAVE_EPOLL
#include <sys/epoll.h>
static int epoll_fd = -1;
static void fdevent_init()
{
/* XXX: what's a good size for the passed in hint? */
epoll_fd = epoll_create(256);
if(epoll_fd < 0) {
perror("epoll_create() failed");
exit(1);
}
/* mark for close-on-exec */
fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
}
static void fdevent_connect(fdevent *fde)
{
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = 0;
ev.data.ptr = fde;
#if 0
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
#endif
}
static void fdevent_disconnect(fdevent *fde)
{
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = 0;
ev.data.ptr = fde;
/* technically we only need to delete if we
** were actively monitoring events, but let's
** be aggressive and do it anyway, just in case
** something's out of sync
*/
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
}
static void fdevent_update(fdevent *fde, unsigned events)
{
struct epoll_event ev;
int active;
active = (fde->state & FDE_EVENTMASK) != 0;
memset(&ev, 0, sizeof(ev));
ev.events = 0;
ev.data.ptr = fde;
if(events & FDE_READ) ev.events |= EPOLLIN;
if(events & FDE_WRITE) ev.events |= EPOLLOUT;
if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
fde->state = (fde->state & FDE_STATEMASK) | events;
if(active) {
/* we're already active. if we're changing to *no*
** events being monitored, we need to delete, otherwise
** we need to just modify
*/
if(ev.events) {
if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
} else {
if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
}
} else {
/* we're not active. if we're watching events, we need
** to add, otherwise we can just do nothing
*/
if(ev.events) {
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
perror("epoll_ctl() failed\n");
exit(1);
}
}
}
}
static void fdevent_process()
{
struct epoll_event events[256];
fdevent *fde;
int i, n;
n = epoll_wait(epoll_fd, events, 256, -1);
if(n < 0) {
if(errno == EINTR) return;
perror("epoll_wait");
exit(1);
}
for(i = 0; i < n; i++) {
struct epoll_event *ev = events + i;
fde = ev->data.ptr;
if(ev->events & EPOLLIN) {
fde->events |= FDE_READ;
}
if(ev->events & EPOLLOUT) {
fde->events |= FDE_WRITE;
}
if(ev->events & (EPOLLERR | EPOLLHUP)) {
fde->events |= FDE_ERROR;
}
if(fde->events) {
if(fde->state & FDE_PENDING) continue;
fde->state |= FDE_PENDING;
fdevent_plist_enqueue(fde);
}
}
}
#else /* USE_SELECT */
#ifdef HAVE_WINSOCK
#include <winsock2.h>
#else
#include <sys/select.h>
#endif
static fd_set read_fds;
static fd_set write_fds;
static fd_set error_fds;
static int select_n = 0;
static void fdevent_init(void)
{
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
}
static void fdevent_connect(fdevent *fde)
{
if(fde->fd >= select_n) {
select_n = fde->fd + 1;
}
}
static void fdevent_disconnect(fdevent *fde)
{
int i, n;
FD_CLR(fde->fd, &read_fds);
FD_CLR(fde->fd, &write_fds);
FD_CLR(fde->fd, &error_fds);
for(n = 0, i = 0; i < select_n; i++) {
if(fd_table[i] != 0) n = i;
}
select_n = n + 1;
}
static void fdevent_update(fdevent *fde, unsigned events)
{
if(events & FDE_READ) {
FD_SET(fde->fd, &read_fds);
} else {
FD_CLR(fde->fd, &read_fds);
}
if(events & FDE_WRITE) {
FD_SET(fde->fd, &write_fds);
} else {
FD_CLR(fde->fd, &write_fds);
}
if(events & FDE_ERROR) {
FD_SET(fde->fd, &error_fds);
} else {
FD_CLR(fde->fd, &error_fds);
}
fde->state = (fde->state & FDE_STATEMASK) | events;
}
/* Looks at fd_table[] for bad FDs and sets bit in fds.
** Returns the number of bad FDs.
*/
static int fdevent_fd_check(fd_set *fds)
{
int i, n = 0;
fdevent *fde;
for(i = 0; i < select_n; i++) {
fde = fd_table[i];
if(fde == 0) continue;
if(fcntl(i, F_GETFL, NULL) < 0) {
FD_SET(i, fds);
n++;
// fde->state |= FDE_DONT_CLOSE;
}
}
return n;
}
#if !DEBUG
static inline void dump_all_fds(const char *extra_msg) {}
#else
static void dump_all_fds(const char *extra_msg)
{
int i;
fdevent *fde;
// per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
size_t max_chars = FD_SETSIZE * 6 + 1;
int printed_out;
#define SAFE_SPRINTF(...) \
do { \
printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
if (printed_out <= 0) { \
D("... snprintf failed.\n"); \
return; \
} \
if (max_chars < (unsigned int)printed_out) { \
D("... snprintf out of space.\n"); \
return; \
} \
pb += printed_out; \
max_chars -= printed_out; \
} while(0)
for(i = 0; i < select_n; i++) {
fde = fd_table[i];
SAFE_SPRINTF("%d", i);
if(fde == 0) {
SAFE_SPRINTF("? ");
continue;
}
if(fcntl(i, F_GETFL, NULL) < 0) {
SAFE_SPRINTF("b");
}
SAFE_SPRINTF(" ");
}
D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
}
#endif
static void fdevent_process()
{
int i, n;
fdevent *fde;
unsigned events;
fd_set rfd, wfd, efd;
memcpy(&rfd, &read_fds, sizeof(fd_set));
memcpy(&wfd, &write_fds, sizeof(fd_set));
memcpy(&efd, &error_fds, sizeof(fd_set));
dump_all_fds("pre select()");
n = select(select_n, &rfd, &wfd, &efd, NULL);
int saved_errno = errno;
D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
dump_all_fds("post select()");
if(n < 0) {
switch(saved_errno) {
case EINTR: return;
case EBADF:
// Can't trust the FD sets after an error.
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_ZERO(&rfd);
break;
default:
D("Unexpected select() error=%d\n", saved_errno);
return;
}
}
if(n <= 0) {
// We fake a read, as the rest of the code assumes
// that errors will be detected at that point.
n = fdevent_fd_check(&rfd);
}
for(i = 0; (i < select_n) && (n > 0); i++) {
events = 0;
if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
if(events) {
fde = fd_table[i];
if(fde == 0)
FATAL("missing fde for fd %d\n", i);
fde->events |= events;
D("got events fde->fd=%d events=%04x, state=%04x\n",
fde->fd, fde->events, fde->state);
if(fde->state & FDE_PENDING) continue;
fde->state |= FDE_PENDING;
fdevent_plist_enqueue(fde);
}
}
}
#endif
static void fdevent_register(fdevent *fde)
{
if(fde->fd < 0) {
FATAL("bogus negative fd (%d)\n", fde->fd);
}
if(fde->fd >= fd_table_max) {
int oldmax = fd_table_max;
if(fde->fd > 32000) {
FATAL("bogus huuuuge fd (%d)\n", fde->fd);
}
if(fd_table_max == 0) {
fdevent_init();
fd_table_max = 256;
}
while(fd_table_max <= fde->fd) {
fd_table_max *= 2;
}
fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
if(fd_table == 0) {
FATAL("could not expand fd_table to %d entries\n", fd_table_max);
}
memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
}
fd_table[fde->fd] = fde;
}
static void fdevent_unregister(fdevent *fde)
{
if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
FATAL("fd out of range (%d)\n", fde->fd);
}
if(fd_table[fde->fd] != fde) {
FATAL("fd_table out of sync [%d]\n", fde->fd);
}
fd_table[fde->fd] = 0;
if(!(fde->state & FDE_DONT_CLOSE)) {
dump_fde(fde, "close");
adb_close(fde->fd);
}
}
static void fdevent_plist_enqueue(fdevent *node)
{
fdevent *list = &list_pending;
node->next = list;
node->prev = list->prev;
node->prev->next = node;
list->prev = node;
}
static void fdevent_plist_remove(fdevent *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = 0;
node->prev = 0;
}
static fdevent *fdevent_plist_dequeue(void)
{
fdevent *list = &list_pending;
fdevent *node = list->next;
if(node == list) return 0;
list->next = node->next;
list->next->prev = list;
node->next = 0;
node->prev = 0;
return node;
}
static void fdevent_call_fdfunc(fdevent* fde)
{
unsigned events = fde->events;
fde->events = 0;
if(!(fde->state & FDE_PENDING)) return;
fde->state &= (~FDE_PENDING);
dump_fde(fde, "callback");
fde->func(fde->fd, events, fde->arg);
}
static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
{
D("subproc handling on fd=%d ev=%04x\n", fd, ev);
// Hook oneself back into the fde's suitable for select() on read.
if((fd < 0) || (fd >= fd_table_max)) {
FATAL("fd %d out of range for fd_table \n", fd);
}
fdevent *fde = fd_table[fd];
fdevent_add(fde, FDE_READ);
if(ev & FDE_READ){
int subproc_fd;
if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
}
if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
D("subproc_fd %d out of range 0, fd_table_max=%d\n",
subproc_fd, fd_table_max);
return;
}
fdevent *subproc_fde = fd_table[subproc_fd];
if(!subproc_fde) {
D("subproc_fd %d cleared from fd_table\n", subproc_fd);
return;
}
if(subproc_fde->fd != subproc_fd) {
// Already reallocated?
D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
return;
}
subproc_fde->force_eof = 1;
int rcount = 0;
ioctl(subproc_fd, FIONREAD, &rcount);
D("subproc with fd=%d has rcount=%d err=%d\n",
subproc_fd, rcount, errno);
if(rcount) {
// If there is data left, it will show up in the select().
// This works because there is no other thread reading that
// data when in this fd_func().
return;
}
D("subproc_fde.state=%04x\n", subproc_fde->state);
subproc_fde->events |= FDE_READ;
if(subproc_fde->state & FDE_PENDING) {
return;
}
subproc_fde->state |= FDE_PENDING;
fdevent_call_fdfunc(subproc_fde);
}
}
fdevent *fdevent_create(int fd, fd_func func, void *arg)
{
fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
if(fde == 0) return 0;
fdevent_install(fde, fd, func, arg);
fde->state |= FDE_CREATED;
return fde;
}
void fdevent_destroy(fdevent *fde)
{
if(fde == 0) return;
if(!(fde->state & FDE_CREATED)) {
FATAL("fde %p not created by fdevent_create()\n", fde);
}
fdevent_remove(fde);
}
void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
{
memset(fde, 0, sizeof(fdevent));
fde->state = FDE_ACTIVE;
fde->fd = fd;
fde->force_eof = 0;
fde->func = func;
fde->arg = arg;
#ifndef HAVE_WINSOCK
fcntl(fd, F_SETFL, O_NONBLOCK);
#endif
fdevent_register(fde);
dump_fde(fde, "connect");
fdevent_connect(fde);
fde->state |= FDE_ACTIVE;
}
void fdevent_remove(fdevent *fde)
{
if(fde->state & FDE_PENDING) {
fdevent_plist_remove(fde);
}
if(fde->state & FDE_ACTIVE) {
fdevent_disconnect(fde);
dump_fde(fde, "disconnect");
fdevent_unregister(fde);
}
fde->state = 0;
fde->events = 0;
}
void fdevent_set(fdevent *fde, unsigned events)
{
events &= FDE_EVENTMASK;
if((fde->state & FDE_EVENTMASK) == events) return;
if(fde->state & FDE_ACTIVE) {
fdevent_update(fde, events);
dump_fde(fde, "update");
}
fde->state = (fde->state & FDE_STATEMASK) | events;
if(fde->state & FDE_PENDING) {
/* if we're pending, make sure
** we don't signal an event that
** is no longer wanted.
*/
fde->events &= (~events);
if(fde->events == 0) {
fdevent_plist_remove(fde);
fde->state &= (~FDE_PENDING);
}
}
}
void fdevent_add(fdevent *fde, unsigned events)
{
fdevent_set(
fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
}
void fdevent_del(fdevent *fde, unsigned events)
{
fdevent_set(
fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
}
void fdevent_subproc_setup()
{
int s[2];
if(adb_socketpair(s)) {
FATAL("cannot create shell-exit socket-pair\n");
}
SHELL_EXIT_NOTIFY_FD = s[0];
fdevent *fde;
fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
if(!fde)
FATAL("cannot create fdevent for shell-exit handler\n");
fdevent_add(fde, FDE_READ);
}
void fdevent_loop()
{
fdevent *fde;
fdevent_subproc_setup();
for(;;) {
D("--- ---- waiting for events\n");
fdevent_process();
while((fde = fdevent_plist_dequeue())) {
fdevent_call_fdfunc(fde);
}
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FDEVENT_H
#define __FDEVENT_H
#include <stdint.h> /* for int64_t */
/* events that may be observed */
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
#define FDE_ERROR 0x0004
#define FDE_TIMEOUT 0x0008
/* features that may be set (via the events set/add/del interface) */
#define FDE_DONT_CLOSE 0x0080
typedef struct fdevent fdevent;
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
/* Allocate and initialize a new fdevent object
* Note: use FD_TIMER as 'fd' to create a fd-less object
* (used to implement timers).
*/
fdevent *fdevent_create(int fd, fd_func func, void *arg);
/* Uninitialize and deallocate an fdevent object that was
** created by fdevent_create()
*/
void fdevent_destroy(fdevent *fde);
/* Initialize an fdevent object that was externally allocated
*/
void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
/* Uninitialize an fdevent object that was initialized by
** fdevent_install()
*/
void fdevent_remove(fdevent *item);
/* Change which events should cause notifications
*/
void fdevent_set(fdevent *fde, unsigned events);
void fdevent_add(fdevent *fde, unsigned events);
void fdevent_del(fdevent *fde, unsigned events);
void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
/* loop forever, handling events.
*/
void fdevent_loop();
struct fdevent
{
fdevent *next;
fdevent *prev;
int fd;
int force_eof;
unsigned short state;
unsigned short events;
fd_func func;
void *arg;
};
#endif
+26
View File
@@ -0,0 +1,26 @@
/* the list of mutexes used by adb */
/* #ifndef __MUTEX_LIST_H
* Do not use an include-guard. This file is included once to declare the locks
* and once in win32 to actually do the runtime initialization.
*/
#ifndef ADB_MUTEX
#error ADB_MUTEX not defined when including this file
#endif
ADB_MUTEX(dns_lock)
ADB_MUTEX(socket_list_lock)
ADB_MUTEX(transport_lock)
#if ADB_HOST
ADB_MUTEX(local_transports_lock)
#endif
ADB_MUTEX(usb_lock)
// Sadly logging to /data/adb/adb-... is not thread safe.
// After modifying adb.h::D() to count invocations:
// DEBUG(jpa):0:Handling main()
// DEBUG(jpa):1:[ usb_init - starting thread ]
// (Oopsies, no :2:, and matching message is also gone.)
// DEBUG(jpa):3:[ usb_thread - opening device ]
// DEBUG(jpa):4:jdwp control socket started (10)
ADB_MUTEX(D_lock)
#undef ADB_MUTEX
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "sysdeps.h"
#include "fdevent.h"
#define TRACE_TAG TRACE_SERVICES
#include "adb.h"
typedef struct stinfo stinfo;
struct stinfo {
void (*func)(int fd, void *cookie);
int fd;
void *cookie;
};
void *service_bootstrap_func(void *x)
{
stinfo *sti = x;
sti->func(sti->fd, sti->cookie);
free(sti);
return 0;
}
static void sideload_service(int s, void *cookie)
{
unsigned char buf[4096];
unsigned count = (unsigned) cookie;
int fd;
fprintf(stderr, "sideload_service invoked\n");
fd = adb_creat(ADB_SIDELOAD_FILENAME, 0644);
if(fd < 0) {
adb_close(s);
return;
}
while(count > 0) {
unsigned xfer = (count > 4096) ? 4096 : count;
if(readx(s, buf, xfer)) break;
if(writex(fd, buf, xfer)) break;
count -= xfer;
}
if(count == 0) {
writex(s, "OKAY", 4);
} else {
writex(s, "FAIL", 4);
}
adb_close(fd);
adb_close(s);
if (count == 0) {
fprintf(stderr, "adbd exiting after successful sideload\n");
sleep(1);
exit(0);
}
}
#if 0
static void echo_service(int fd, void *cookie)
{
char buf[4096];
int r;
char *p;
int c;
for(;;) {
r = read(fd, buf, 4096);
if(r == 0) goto done;
if(r < 0) {
if(errno == EINTR) continue;
else goto done;
}
c = r;
p = buf;
while(c > 0) {
r = write(fd, p, c);
if(r > 0) {
c -= r;
p += r;
continue;
}
if((r < 0) && (errno == EINTR)) continue;
goto done;
}
}
done:
close(fd);
}
#endif
static int create_service_thread(void (*func)(int, void *), void *cookie)
{
stinfo *sti;
adb_thread_t t;
int s[2];
if(adb_socketpair(s)) {
printf("cannot create service socket pair\n");
return -1;
}
sti = malloc(sizeof(stinfo));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = func;
sti->cookie = cookie;
sti->fd = s[1];
if(adb_thread_create( &t, service_bootstrap_func, sti)){
free(sti);
adb_close(s[0]);
adb_close(s[1]);
printf("cannot create service thread\n");
return -1;
}
D("service thread started, %d:%d\n",s[0], s[1]);
return s[0];
}
int service_to_fd(const char *name)
{
int ret = -1;
if (!strncmp(name, "sideload:", 9)) {
ret = create_service_thread(sideload_service, (void*) atoi(name + 9));
#if 0
} else if(!strncmp(name, "echo:", 5)){
ret = create_service_thread(echo_service, 0);
#endif
}
if (ret >= 0) {
close_on_exec(ret);
}
return ret;
}
+830
View File
@@ -0,0 +1,830 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include "sysdeps.h"
#define TRACE_TAG TRACE_SOCKETS
#include "adb.h"
ADB_MUTEX_DEFINE( socket_list_lock );
static void local_socket_close_locked(asocket *s);
int sendfailmsg(int fd, const char *reason)
{
char buf[9];
int len;
len = strlen(reason);
if(len > 0xffff) len = 0xffff;
snprintf(buf, sizeof buf, "FAIL%04x", len);
if(writex(fd, buf, 8)) return -1;
return writex(fd, reason, len);
}
//extern int online;
static unsigned local_socket_next_id = 1;
static asocket local_socket_list = {
.next = &local_socket_list,
.prev = &local_socket_list,
};
/* the the list of currently closing local sockets.
** these have no peer anymore, but still packets to
** write to their fd.
*/
static asocket local_socket_closing_list = {
.next = &local_socket_closing_list,
.prev = &local_socket_closing_list,
};
asocket *find_local_socket(unsigned id)
{
asocket *s;
asocket *result = NULL;
adb_mutex_lock(&socket_list_lock);
for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
if (s->id == id) {
result = s;
break;
}
}
adb_mutex_unlock(&socket_list_lock);
return result;
}
static void
insert_local_socket(asocket* s, asocket* list)
{
s->next = list;
s->prev = s->next->prev;
s->prev->next = s;
s->next->prev = s;
}
void install_local_socket(asocket *s)
{
adb_mutex_lock(&socket_list_lock);
s->id = local_socket_next_id++;
insert_local_socket(s, &local_socket_list);
adb_mutex_unlock(&socket_list_lock);
}
void remove_socket(asocket *s)
{
// socket_list_lock should already be held
if (s->prev && s->next)
{
s->prev->next = s->next;
s->next->prev = s->prev;
s->next = 0;
s->prev = 0;
s->id = 0;
}
}
void close_all_sockets(atransport *t)
{
asocket *s;
/* this is a little gross, but since s->close() *will* modify
** the list out from under you, your options are limited.
*/
adb_mutex_lock(&socket_list_lock);
restart:
for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
if(s->transport == t || (s->peer && s->peer->transport == t)) {
local_socket_close_locked(s);
goto restart;
}
}
adb_mutex_unlock(&socket_list_lock);
}
static int local_socket_enqueue(asocket *s, apacket *p)
{
D("LS(%d): enqueue %d\n", s->id, p->len);
p->ptr = p->data;
/* if there is already data queue'd, we will receive
** events when it's time to write. just add this to
** the tail
*/
if(s->pkt_first) {
goto enqueue;
}
/* write as much as we can, until we
** would block or there is an error/eof
*/
while(p->len > 0) {
int r = adb_write(s->fd, p->ptr, p->len);
if(r > 0) {
p->len -= r;
p->ptr += r;
continue;
}
if((r == 0) || (errno != EAGAIN)) {
D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
s->close(s);
return 1; /* not ready (error) */
} else {
break;
}
}
if(p->len == 0) {
put_apacket(p);
return 0; /* ready for more data */
}
enqueue:
p->next = 0;
if(s->pkt_first) {
s->pkt_last->next = p;
} else {
s->pkt_first = p;
}
s->pkt_last = p;
/* make sure we are notified when we can drain the queue */
fdevent_add(&s->fde, FDE_WRITE);
return 1; /* not ready (backlog) */
}
static void local_socket_ready(asocket *s)
{
/* far side is ready for data, pay attention to
readable events */
fdevent_add(&s->fde, FDE_READ);
// D("LS(%d): ready()\n", s->id);
}
static void local_socket_close(asocket *s)
{
adb_mutex_lock(&socket_list_lock);
local_socket_close_locked(s);
adb_mutex_unlock(&socket_list_lock);
}
// be sure to hold the socket list lock when calling this
static void local_socket_destroy(asocket *s)
{
apacket *p, *n;
D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
/* IMPORTANT: the remove closes the fd
** that belongs to this socket
*/
fdevent_remove(&s->fde);
/* dispose of any unwritten data */
for(p = s->pkt_first; p; p = n) {
D("LS(%d): discarding %d bytes\n", s->id, p->len);
n = p->next;
put_apacket(p);
}
remove_socket(s);
free(s);
}
static void local_socket_close_locked(asocket *s)
{
D("entered. LS(%d) fd=%d\n", s->id, s->fd);
if(s->peer) {
D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
s->id, s->peer->id, s->peer->fd);
s->peer->peer = 0;
// tweak to avoid deadlock
if (s->peer->close == local_socket_close) {
local_socket_close_locked(s->peer);
} else {
s->peer->close(s->peer);
}
s->peer = 0;
}
/* If we are already closing, or if there are no
** pending packets, destroy immediately
*/
if (s->closing || s->pkt_first == NULL) {
int id = s->id;
local_socket_destroy(s);
D("LS(%d): closed\n", id);
return;
}
/* otherwise, put on the closing list
*/
D("LS(%d): closing\n", s->id);
s->closing = 1;
fdevent_del(&s->fde, FDE_READ);
remove_socket(s);
D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
insert_local_socket(s, &local_socket_closing_list);
}
static void local_socket_event_func(int fd, unsigned ev, void *_s)
{
asocket *s = _s;
D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
/* put the FDE_WRITE processing before the FDE_READ
** in order to simplify the code.
*/
if(ev & FDE_WRITE){
apacket *p;
while((p = s->pkt_first) != 0) {
while(p->len > 0) {
int r = adb_write(fd, p->ptr, p->len);
if(r > 0) {
p->ptr += r;
p->len -= r;
continue;
}
if(r < 0) {
/* returning here is ok because FDE_READ will
** be processed in the next iteration loop
*/
if(errno == EAGAIN) return;
if(errno == EINTR) continue;
}
D(" closing after write because r=%d and errno is %d\n", r, errno);
s->close(s);
return;
}
if(p->len == 0) {
s->pkt_first = p->next;
if(s->pkt_first == 0) s->pkt_last = 0;
put_apacket(p);
}
}
/* if we sent the last packet of a closing socket,
** we can now destroy it.
*/
if (s->closing) {
D(" closing because 'closing' is set after write\n");
s->close(s);
return;
}
/* no more packets queued, so we can ignore
** writable events again and tell our peer
** to resume writing
*/
fdevent_del(&s->fde, FDE_WRITE);
s->peer->ready(s->peer);
}
if(ev & FDE_READ){
apacket *p = get_apacket();
unsigned char *x = p->data;
size_t avail = MAX_PAYLOAD;
int r;
int is_eof = 0;
while(avail > 0) {
r = adb_read(fd, x, avail);
D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
if(r > 0) {
avail -= r;
x += r;
continue;
}
if(r < 0) {
if(errno == EAGAIN) break;
if(errno == EINTR) continue;
}
/* r = 0 or unhandled error */
is_eof = 1;
break;
}
D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
s->id, s->fd, r, is_eof, s->fde.force_eof);
if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
put_apacket(p);
} else {
p->len = MAX_PAYLOAD - avail;
r = s->peer->enqueue(s->peer, p);
D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
if(r < 0) {
/* error return means they closed us as a side-effect
** and we must return immediately.
**
** note that if we still have buffered packets, the
** socket will be placed on the closing socket list.
** this handler function will be called again
** to process FDE_WRITE events.
*/
return;
}
if(r > 0) {
/* if the remote cannot accept further events,
** we disable notification of READs. They'll
** be enabled again when we get a call to ready()
*/
fdevent_del(&s->fde, FDE_READ);
}
}
/* Don't allow a forced eof if data is still there */
if((s->fde.force_eof && !r) || is_eof) {
D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
s->close(s);
}
}
if(ev & FDE_ERROR){
/* this should be caught be the next read or write
** catching it here means we may skip the last few
** bytes of readable data.
*/
// s->close(s);
D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
return;
}
}
asocket *create_local_socket(int fd)
{
asocket *s = calloc(1, sizeof(asocket));
if (s == NULL) fatal("cannot allocate socket");
s->fd = fd;
s->enqueue = local_socket_enqueue;
s->ready = local_socket_ready;
s->close = local_socket_close;
install_local_socket(s);
fdevent_install(&s->fde, fd, local_socket_event_func, s);
/* fdevent_add(&s->fde, FDE_ERROR); */
//fprintf(stderr, "Created local socket in create_local_socket \n");
D("LS(%d): created (fd=%d)\n", s->id, s->fd);
return s;
}
asocket *create_local_service_socket(const char *name)
{
asocket *s;
int fd;
fd = service_to_fd(name);
if(fd < 0) return 0;
s = create_local_socket(fd);
D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
return s;
}
#if ADB_HOST
static asocket *create_host_service_socket(const char *name, const char* serial)
{
asocket *s;
s = host_service_to_socket(name, serial);
if (s != NULL) {
D("LS(%d) bound to '%s'\n", s->id, name);
return s;
}
return s;
}
#endif /* ADB_HOST */
/* a Remote socket is used to send/receive data to/from a given transport object
** it needs to be closed when the transport is forcibly destroyed by the user
*/
typedef struct aremotesocket {
asocket socket;
adisconnect disconnect;
} aremotesocket;
static int remote_socket_enqueue(asocket *s, apacket *p)
{
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
s->id, s->fd, s->peer->fd);
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
p->msg.data_length = p->len;
send_packet(p, s->transport);
return 1;
}
static void remote_socket_ready(asocket *s)
{
D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
s->id, s->fd, s->peer->fd);
apacket *p = get_apacket();
p->msg.command = A_OKAY;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
send_packet(p, s->transport);
}
static void remote_socket_close(asocket *s)
{
D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
s->id, s->fd, s->peer?s->peer->fd:-1);
apacket *p = get_apacket();
p->msg.command = A_CLSE;
if(s->peer) {
p->msg.arg0 = s->peer->id;
s->peer->peer = 0;
D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
s->id, s->peer->id, s->peer->fd);
s->peer->close(s->peer);
}
p->msg.arg1 = s->id;
send_packet(p, s->transport);
D("RS(%d): closed\n", s->id);
remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
free(s);
}
static void remote_socket_disconnect(void* _s, atransport* t)
{
asocket* s = _s;
asocket* peer = s->peer;
D("remote_socket_disconnect RS(%d)\n", s->id);
if (peer) {
peer->peer = NULL;
peer->close(peer);
}
remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
free(s);
}
asocket *create_remote_socket(unsigned id, atransport *t)
{
asocket *s = calloc(1, sizeof(aremotesocket));
adisconnect* dis = &((aremotesocket*)s)->disconnect;
if (s == NULL) fatal("cannot allocate socket");
s->id = id;
s->enqueue = remote_socket_enqueue;
s->ready = remote_socket_ready;
s->close = remote_socket_close;
s->transport = t;
dis->func = remote_socket_disconnect;
dis->opaque = s;
add_transport_disconnect( t, dis );
D("RS(%d): created\n", s->id);
return s;
}
void connect_to_remote(asocket *s, const char *destination)
{
D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
apacket *p = get_apacket();
int len = strlen(destination) + 1;
if(len > (MAX_PAYLOAD-1)) {
fatal("destination oversized");
}
D("LS(%d): connect('%s')\n", s->id, destination);
p->msg.command = A_OPEN;
p->msg.arg0 = s->id;
p->msg.data_length = len;
strcpy((char*) p->data, destination);
send_packet(p, s->transport);
}
/* this is used by magic sockets to rig local sockets to
send the go-ahead message when they connect */
static void local_socket_ready_notify(asocket *s)
{
s->ready = local_socket_ready;
s->close = local_socket_close;
adb_write(s->fd, "OKAY", 4);
s->ready(s);
}
/* this is used by magic sockets to rig local sockets to
send the failure message if they are closed before
connected (to avoid closing them without a status message) */
static void local_socket_close_notify(asocket *s)
{
s->ready = local_socket_ready;
s->close = local_socket_close;
sendfailmsg(s->fd, "closed");
s->close(s);
}
unsigned unhex(unsigned char *s, int len)
{
unsigned n = 0, c;
while(len-- > 0) {
switch((c = *s++)) {
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9':
c -= '0';
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
c = c - 'a' + 10;
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
c = c - 'A' + 10;
break;
default:
return 0xffffffff;
}
n = (n << 4) | c;
}
return n;
}
/* skip_host_serial return the position in a string
skipping over the 'serial' parameter in the ADB protocol,
where parameter string may be a host:port string containing
the protocol delimiter (colon). */
char *skip_host_serial(char *service) {
char *first_colon, *serial_end;
first_colon = strchr(service, ':');
if (!first_colon) {
/* No colon in service string. */
return NULL;
}
serial_end = first_colon;
if (isdigit(serial_end[1])) {
serial_end++;
while ((*serial_end) && isdigit(*serial_end)) {
serial_end++;
}
if ((*serial_end) != ':') {
// Something other than numbers was found, reset the end.
serial_end = first_colon;
}
}
return serial_end;
}
static int smart_socket_enqueue(asocket *s, apacket *p)
{
unsigned len;
#if ADB_HOST
char *service = NULL;
char* serial = NULL;
transport_type ttype = kTransportAny;
#endif
D("SS(%d): enqueue %d\n", s->id, p->len);
if(s->pkt_first == 0) {
s->pkt_first = p;
s->pkt_last = p;
} else {
if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
D("SS(%d): overflow\n", s->id);
put_apacket(p);
goto fail;
}
memcpy(s->pkt_first->data + s->pkt_first->len,
p->data, p->len);
s->pkt_first->len += p->len;
put_apacket(p);
p = s->pkt_first;
}
/* don't bother if we can't decode the length */
if(p->len < 4) return 0;
len = unhex(p->data, 4);
if((len < 1) || (len > 1024)) {
D("SS(%d): bad size (%d)\n", s->id, len);
goto fail;
}
D("SS(%d): len is %d\n", s->id, len );
/* can't do anything until we have the full header */
if((len + 4) > p->len) {
D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
return 0;
}
p->data[len + 4] = 0;
D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
#if ADB_HOST
service = (char *)p->data + 4;
if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
char* serial_end;
service += strlen("host-serial:");
// serial number should follow "host:" and could be a host:port string.
serial_end = skip_host_serial(service);
if (serial_end) {
*serial_end = 0; // terminate string
serial = service;
service = serial_end + 1;
}
} else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
ttype = kTransportUsb;
service += strlen("host-usb:");
} else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
ttype = kTransportLocal;
service += strlen("host-local:");
} else if (!strncmp(service, "host:", strlen("host:"))) {
ttype = kTransportAny;
service += strlen("host:");
} else {
service = NULL;
}
if (service) {
asocket *s2;
/* some requests are handled immediately -- in that
** case the handle_host_request() routine has sent
** the OKAY or FAIL message and all we have to do
** is clean up.
*/
if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
/* XXX fail message? */
D( "SS(%d): handled host service '%s'\n", s->id, service );
goto fail;
}
if (!strncmp(service, "transport", strlen("transport"))) {
D( "SS(%d): okay transport\n", s->id );
p->len = 0;
return 0;
}
/* try to find a local service with this name.
** if no such service exists, we'll fail out
** and tear down here.
*/
s2 = create_host_service_socket(service, serial);
if(s2 == 0) {
D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
sendfailmsg(s->peer->fd, "unknown host service");
goto fail;
}
/* we've connected to a local host service,
** so we make our peer back into a regular
** local socket and bind it to the new local
** service socket, acknowledge the successful
** connection, and close this smart socket now
** that its work is done.
*/
adb_write(s->peer->fd, "OKAY", 4);
s->peer->ready = local_socket_ready;
s->peer->close = local_socket_close;
s->peer->peer = s2;
s2->peer = s->peer;
s->peer = 0;
D( "SS(%d): okay\n", s->id );
s->close(s);
/* initial state is "ready" */
s2->ready(s2);
return 0;
}
#else /* !ADB_HOST */
if (s->transport == NULL) {
char* error_string = "unknown failure";
s->transport = acquire_one_transport (CS_ANY,
kTransportAny, NULL, &error_string);
if (s->transport == NULL) {
sendfailmsg(s->peer->fd, error_string);
goto fail;
}
}
#endif
if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
/* if there's no remote we fail the connection
** right here and terminate it
*/
sendfailmsg(s->peer->fd, "device offline (x)");
goto fail;
}
/* instrument our peer to pass the success or fail
** message back once it connects or closes, then
** detach from it, request the connection, and
** tear down
*/
s->peer->ready = local_socket_ready_notify;
s->peer->close = local_socket_close_notify;
s->peer->peer = 0;
/* give him our transport and upref it */
s->peer->transport = s->transport;
connect_to_remote(s->peer, (char*) (p->data + 4));
s->peer = 0;
s->close(s);
return 1;
fail:
/* we're going to close our peer as a side-effect, so
** return -1 to signal that state to the local socket
** who is enqueueing against us
*/
s->close(s);
return -1;
}
static void smart_socket_ready(asocket *s)
{
D("SS(%d): ready\n", s->id);
}
static void smart_socket_close(asocket *s)
{
D("SS(%d): closed\n", s->id);
if(s->pkt_first){
put_apacket(s->pkt_first);
}
if(s->peer) {
s->peer->peer = 0;
s->peer->close(s->peer);
s->peer = 0;
}
free(s);
}
asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
{
D("Creating smart socket \n");
asocket *s = calloc(1, sizeof(asocket));
if (s == NULL) fatal("cannot allocate socket");
s->enqueue = smart_socket_enqueue;
s->ready = smart_socket_ready;
s->close = smart_socket_close;
s->extra = action_cb;
D("SS(%d): created %p\n", s->id, action_cb);
return s;
}
void smart_socket_action(asocket *s, const char *act)
{
}
void connect_to_smartsocket(asocket *s)
{
D("Connecting to smart socket \n");
asocket *ss = create_smart_socket(smart_socket_action);
s->peer = ss;
ss->peer = s;
s->ready(s);
}
+495
View File
@@ -0,0 +1,495 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* this file contains system-dependent definitions used by ADB
* they're related to threads, sockets and file descriptors
*/
#ifndef _ADB_SYSDEPS_H
#define _ADB_SYSDEPS_H
#ifdef __CYGWIN__
# undef _WIN32
#endif
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <process.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#define OS_PATH_SEPARATOR '\\'
#define OS_PATH_SEPARATOR_STR "\\"
typedef CRITICAL_SECTION adb_mutex_t;
#define ADB_MUTEX_DEFINE(x) adb_mutex_t x
/* declare all mutexes */
/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
#define ADB_MUTEX(x) extern adb_mutex_t x;
#include "mutex_list.h"
extern void adb_sysdeps_init(void);
static __inline__ void adb_mutex_lock( adb_mutex_t* lock )
{
EnterCriticalSection( lock );
}
static __inline__ void adb_mutex_unlock( adb_mutex_t* lock )
{
LeaveCriticalSection( lock );
}
typedef struct { unsigned tid; } adb_thread_t;
typedef void* (*adb_thread_func_t)(void* arg);
typedef void (*win_thread_func_t)(void* arg);
static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg)
{
thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
if (thread->tid == (unsigned)-1L) {
return -1;
}
return 0;
}
static __inline__ void close_on_exec(int fd)
{
/* nothing really */
}
extern void disable_tcp_nagle(int fd);
#define lstat stat /* no symlinks on Win32 */
#define S_ISLNK(m) 0 /* no symlinks on Win32 */
static __inline__ int adb_unlink(const char* path)
{
int rc = unlink(path);
if (rc == -1 && errno == EACCES) {
/* unlink returns EACCES when the file is read-only, so we first */
/* try to make it writable, then unlink again... */
rc = chmod(path, _S_IREAD|_S_IWRITE );
if (rc == 0)
rc = unlink(path);
}
return rc;
}
#undef unlink
#define unlink ___xxx_unlink
static __inline__ int adb_mkdir(const char* path, int mode)
{
return _mkdir(path);
}
#undef mkdir
#define mkdir ___xxx_mkdir
extern int adb_open(const char* path, int options);
extern int adb_creat(const char* path, int mode);
extern int adb_read(int fd, void* buf, int len);
extern int adb_write(int fd, const void* buf, int len);
extern int adb_lseek(int fd, int pos, int where);
extern int adb_shutdown(int fd);
extern int adb_close(int fd);
static __inline__ int unix_close(int fd)
{
return close(fd);
}
#undef close
#define close ____xxx_close
static __inline__ int unix_read(int fd, void* buf, size_t len)
{
return read(fd, buf, len);
}
#undef read
#define read ___xxx_read
static __inline__ int unix_write(int fd, const void* buf, size_t len)
{
return write(fd, buf, len);
}
#undef write
#define write ___xxx_write
static __inline__ int adb_open_mode(const char* path, int options, int mode)
{
return adb_open(path, options);
}
static __inline__ int unix_open(const char* path, int options,...)
{
if ((options & O_CREAT) == 0)
{
return open(path, options);
}
else
{
int mode;
va_list args;
va_start( args, options );
mode = va_arg( args, int );
va_end( args );
return open(path, options, mode);
}
}
#define open ___xxx_unix_open
/* normally provided by <cutils/misc.h> */
extern void* load_file(const char* pathname, unsigned* psize);
/* normally provided by <cutils/sockets.h> */
extern int socket_loopback_client(int port, int type);
extern int socket_network_client(const char *host, int port, int type);
extern int socket_loopback_server(int port, int type);
extern int socket_inaddr_any_server(int port, int type);
/* normally provided by "fdevent.h" */
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
#define FDE_ERROR 0x0004
#define FDE_DONT_CLOSE 0x0080
typedef struct fdevent fdevent;
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
fdevent *fdevent_create(int fd, fd_func func, void *arg);
void fdevent_destroy(fdevent *fde);
void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
void fdevent_remove(fdevent *item);
void fdevent_set(fdevent *fde, unsigned events);
void fdevent_add(fdevent *fde, unsigned events);
void fdevent_del(fdevent *fde, unsigned events);
void fdevent_loop();
struct fdevent {
fdevent *next;
fdevent *prev;
int fd;
int force_eof;
unsigned short state;
unsigned short events;
fd_func func;
void *arg;
};
static __inline__ void adb_sleep_ms( int mseconds )
{
Sleep( mseconds );
}
extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
#undef accept
#define accept ___xxx_accept
static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
{
int opt = bufsize;
return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
}
extern int adb_socketpair( int sv[2] );
static __inline__ char* adb_dirstart( const char* path )
{
char* p = strchr(path, '/');
char* p2 = strchr(path, '\\');
if ( !p )
p = p2;
else if ( p2 && p2 > p )
p = p2;
return p;
}
static __inline__ char* adb_dirstop( const char* path )
{
char* p = strrchr(path, '/');
char* p2 = strrchr(path, '\\');
if ( !p )
p = p2;
else if ( p2 && p2 > p )
p = p2;
return p;
}
static __inline__ int adb_is_absolute_host_path( const char* path )
{
return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
}
#else /* !_WIN32 a.k.a. Unix */
#include "fdevent.h"
#include <cutils/sockets.h>
#include <cutils/properties.h>
#include <cutils/misc.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#define OS_PATH_SEPARATOR '/'
#define OS_PATH_SEPARATOR_STR "/"
typedef pthread_mutex_t adb_mutex_t;
#define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#define adb_mutex_init pthread_mutex_init
#define adb_mutex_lock pthread_mutex_lock
#define adb_mutex_unlock pthread_mutex_unlock
#define adb_mutex_destroy pthread_mutex_destroy
#define ADB_MUTEX_DEFINE(m) adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER
#define adb_cond_t pthread_cond_t
#define adb_cond_init pthread_cond_init
#define adb_cond_wait pthread_cond_wait
#define adb_cond_broadcast pthread_cond_broadcast
#define adb_cond_signal pthread_cond_signal
#define adb_cond_destroy pthread_cond_destroy
/* declare all mutexes */
#define ADB_MUTEX(x) extern adb_mutex_t x;
#include "mutex_list.h"
static __inline__ void close_on_exec(int fd)
{
fcntl( fd, F_SETFD, FD_CLOEXEC );
}
static __inline__ int unix_open(const char* path, int options,...)
{
if ((options & O_CREAT) == 0)
{
return open(path, options);
}
else
{
int mode;
va_list args;
va_start( args, options );
mode = va_arg( args, int );
va_end( args );
return open(path, options, mode);
}
}
static __inline__ int adb_open_mode( const char* pathname, int options, int mode )
{
return open( pathname, options, mode );
}
static __inline__ int adb_open( const char* pathname, int options )
{
int fd = open( pathname, options );
if (fd < 0)
return -1;
close_on_exec( fd );
return fd;
}
#undef open
#define open ___xxx_open
static __inline__ int adb_shutdown(int fd)
{
return shutdown(fd, SHUT_RDWR);
}
#undef shutdown
#define shutdown ____xxx_shutdown
static __inline__ int adb_close(int fd)
{
return close(fd);
}
#undef close
#define close ____xxx_close
static __inline__ int adb_read(int fd, void* buf, size_t len)
{
return read(fd, buf, len);
}
#undef read
#define read ___xxx_read
static __inline__ int adb_write(int fd, const void* buf, size_t len)
{
return write(fd, buf, len);
}
#undef write
#define write ___xxx_write
static __inline__ int adb_lseek(int fd, int pos, int where)
{
return lseek(fd, pos, where);
}
#undef lseek
#define lseek ___xxx_lseek
static __inline__ int adb_unlink(const char* path)
{
return unlink(path);
}
#undef unlink
#define unlink ___xxx_unlink
static __inline__ int adb_creat(const char* path, int mode)
{
int fd = creat(path, mode);
if ( fd < 0 )
return -1;
close_on_exec(fd);
return fd;
}
#undef creat
#define creat ___xxx_creat
static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
{
int fd;
fd = accept(serverfd, addr, addrlen);
if (fd >= 0)
close_on_exec(fd);
return fd;
}
#undef accept
#define accept ___xxx_accept
#define unix_read adb_read
#define unix_write adb_write
#define unix_close adb_close
typedef pthread_t adb_thread_t;
typedef void* (*adb_thread_func_t)( void* arg );
static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg )
{
pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
return pthread_create( pthread, &attr, start, arg );
}
static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
{
int opt = bufsize;
return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
}
static __inline__ void disable_tcp_nagle(int fd)
{
int on = 1;
setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
}
static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] )
{
return socketpair( d, type, protocol, sv );
}
static __inline__ int adb_socketpair( int sv[2] )
{
int rc;
rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
if (rc < 0)
return -1;
close_on_exec( sv[0] );
close_on_exec( sv[1] );
return 0;
}
#undef socketpair
#define socketpair ___xxx_socketpair
static __inline__ void adb_sleep_ms( int mseconds )
{
usleep( mseconds*1000 );
}
static __inline__ int adb_mkdir(const char* path, int mode)
{
return mkdir(path, mode);
}
#undef mkdir
#define mkdir ___xxx_mkdir
static __inline__ void adb_sysdeps_init(void)
{
}
static __inline__ char* adb_dirstart(const char* path)
{
return strchr(path, '/');
}
static __inline__ char* adb_dirstop(const char* path)
{
return strrchr(path, '/');
}
static __inline__ int adb_is_absolute_host_path( const char* path )
{
return path[0] == '/';
}
#endif /* !_WIN32 */
#endif /* _ADB_SYSDEPS_H */
+1081
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __TRANSPORT_H
#define __TRANSPORT_H
/* convenience wrappers around read/write that will retry on
** EINTR and/or short read/write. Returns 0 on success, -1
** on error or EOF.
*/
int readx(int fd, void *ptr, size_t len);
int writex(int fd, const void *ptr, size_t len);
#endif /* __TRANSPORT_H */
+148
View File
@@ -0,0 +1,148 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysdeps.h>
#define TRACE_TAG TRACE_TRANSPORT
#include "adb.h"
#if ADB_HOST
#include "usb_vendors.h"
#endif
#ifdef HAVE_BIG_ENDIAN
#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
static inline void fix_endians(apacket *p)
{
p->msg.command = H4(p->msg.command);
p->msg.arg0 = H4(p->msg.arg0);
p->msg.arg1 = H4(p->msg.arg1);
p->msg.data_length = H4(p->msg.data_length);
p->msg.data_check = H4(p->msg.data_check);
p->msg.magic = H4(p->msg.magic);
}
unsigned host_to_le32(unsigned n)
{
return H4(n);
}
#else
#define fix_endians(p) do {} while (0)
unsigned host_to_le32(unsigned n)
{
return n;
}
#endif
static int remote_read(apacket *p, atransport *t)
{
if(usb_read(t->usb, &p->msg, sizeof(amessage))){
D("remote usb: read terminated (message)\n");
return -1;
}
fix_endians(p);
if(check_header(p)) {
D("remote usb: check_header failed\n");
return -1;
}
if(p->msg.data_length) {
if(usb_read(t->usb, p->data, p->msg.data_length)){
D("remote usb: terminated (data)\n");
return -1;
}
}
if(check_data(p)) {
D("remote usb: check_data failed\n");
return -1;
}
return 0;
}
static int remote_write(apacket *p, atransport *t)
{
unsigned size = p->msg.data_length;
fix_endians(p);
if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
D("remote usb: 1 - write terminated\n");
return -1;
}
if(p->msg.data_length == 0) return 0;
if(usb_write(t->usb, &p->data, size)) {
D("remote usb: 2 - write terminated\n");
return -1;
}
return 0;
}
static void remote_close(atransport *t)
{
usb_close(t->usb);
t->usb = 0;
}
static void remote_kick(atransport *t)
{
usb_kick(t->usb);
}
void init_usb_transport(atransport *t, usb_handle *h, int state)
{
D("transport: usb\n");
t->close = remote_close;
t->kick = remote_kick;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sync_token = 1;
t->connection_state = state;
t->type = kTransportUsb;
t->usb = h;
#if ADB_HOST
HOST = 1;
#else
HOST = 0;
#endif
}
#if ADB_HOST
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
{
unsigned i;
for (i = 0; i < vendorIdCount; i++) {
if (vid == vendorIds[i]) {
if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
usb_protocol == ADB_PROTOCOL) {
return 1;
}
return 0;
}
}
return 0;
}
#endif
+157
View File
@@ -0,0 +1,157 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include "sysdeps.h"
#define TRACE_TAG TRACE_USB
#include "adb.h"
struct usb_handle
{
int fd;
adb_cond_t notify;
adb_mutex_t lock;
};
void usb_cleanup()
{
// nothing to do here
}
static void *usb_open_thread(void *x)
{
struct usb_handle *usb = (struct usb_handle *)x;
int fd;
while (1) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
while (usb->fd != -1)
adb_cond_wait(&usb->notify, &usb->lock);
adb_mutex_unlock(&usb->lock);
D("[ usb_thread - opening device ]\n");
do {
/* XXX use inotify? */
fd = unix_open("/dev/android_adb", O_RDWR);
if (fd < 0) {
// to support older kernels
fd = unix_open("/dev/android", O_RDWR);
}
if (fd < 0) {
adb_sleep_ms(1000);
}
} while (fd < 0);
D("[ opening device succeeded ]\n");
close_on_exec(fd);
usb->fd = fd;
D("[ usb_thread - registering device ]\n");
register_usb_transport(usb, 0, 1);
}
// never gets here
return 0;
}
int usb_write(usb_handle *h, const void *data, int len)
{
int n;
D("about to write (fd=%d, len=%d)\n", h->fd, len);
n = adb_write(h->fd, data, len);
if(n != len) {
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
h->fd, n, errno, strerror(errno));
return -1;
}
D("[ done fd=%d ]\n", h->fd);
return 0;
}
int usb_read(usb_handle *h, void *data, int len)
{
int n;
D("about to read (fd=%d, len=%d)\n", h->fd, len);
n = adb_read(h->fd, data, len);
if(n != len) {
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
h->fd, n, errno, strerror(errno));
return -1;
}
D("[ done fd=%d ]\n", h->fd);
return 0;
}
void usb_init()
{
usb_handle *h;
adb_thread_t tid;
int fd;
h = calloc(1, sizeof(usb_handle));
h->fd = -1;
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
// Open the file /dev/android_adb_enable to trigger
// the enabling of the adb USB function in the kernel.
// We never touch this file again - just leave it open
// indefinitely so the kernel will know when we are running
// and when we are not.
fd = unix_open("/dev/android_adb_enable", O_RDWR);
if (fd < 0) {
D("failed to open /dev/android_adb_enable\n");
} else {
close_on_exec(fd);
}
D("[ usb_init - starting thread ]\n");
if(adb_thread_create(&tid, usb_open_thread, h)){
fatal_errno("cannot create usb thread");
}
}
void usb_kick(usb_handle *h)
{
D("usb_kick\n");
adb_mutex_lock(&h->lock);
adb_close(h->fd);
h->fd = -1;
// notify usb_open_thread that we are disconnected
adb_cond_signal(&h->notify);
adb_mutex_unlock(&h->lock);
}
int usb_close(usb_handle *h)
{
// nothing to do here
return 0;
}
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
char*
buff_addc (char* buff, char* buffEnd, int c)
{
int avail = buffEnd - buff;
if (avail <= 0) /* already in overflow mode */
return buff;
if (avail == 1) { /* overflowing, the last byte is reserved for zero */
buff[0] = 0;
return buff + 1;
}
buff[0] = (char) c; /* add char and terminating zero */
buff[1] = 0;
return buff + 1;
}
char*
buff_adds (char* buff, char* buffEnd, const char* s)
{
int slen = strlen(s);
return buff_addb(buff, buffEnd, s, slen);
}
char*
buff_addb (char* buff, char* buffEnd, const void* data, int len)
{
int avail = (buffEnd - buff);
if (avail <= 0 || len <= 0) /* already overflowing */
return buff;
if (len > avail)
len = avail;
memcpy(buff, data, len);
buff += len;
/* ensure there is a terminating zero */
if (buff >= buffEnd) { /* overflow */
buff[-1] = 0;
} else
buff[0] = 0;
return buff;
}
char*
buff_add (char* buff, char* buffEnd, const char* format, ... )
{
int avail;
avail = (buffEnd - buff);
if (avail > 0) {
va_list args;
int nn;
va_start(args, format);
nn = vsnprintf( buff, avail, format, args);
va_end(args);
if (nn < 0) {
/* some C libraries return -1 in case of overflow,
* but they will also do that if the format spec is
* invalid. We assume ADB is not buggy enough to
* trigger that last case. */
nn = avail;
}
else if (nn > avail) {
nn = avail;
}
buff += nn;
/* ensure that there is a terminating zero */
if (buff >= buffEnd)
buff[-1] = 0;
else
buff[0] = 0;
}
return buff;
}
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _ADB_UTILS_H
#define _ADB_UTILS_H
/* bounded buffer functions */
/* all these functions are used to append data to a bounded buffer.
*
* after each operation, the buffer is guaranteed to be zero-terminated,
* even in the case of an overflow. they all return the new buffer position
* which allows one to use them in succession, only checking for overflows
* at the end. For example:
*
* BUFF_DECL(temp,p,end,1024);
* char* p;
*
* p = buff_addc(temp, end, '"');
* p = buff_adds(temp, end, string);
* p = buff_addc(temp, end, '"');
*
* if (p >= end) {
* overflow detected. note that 'temp' is
* zero-terminated for safety.
* }
* return strdup(temp);
*/
/* tries to add a character to the buffer, in case of overflow
* this will only write a terminating zero and return buffEnd.
*/
char* buff_addc (char* buff, char* buffEnd, int c);
/* tries to add a string to the buffer */
char* buff_adds (char* buff, char* buffEnd, const char* s);
/* tries to add a bytes to the buffer. the input can contain zero bytes,
* but a terminating zero will always be appended at the end anyway
*/
char* buff_addb (char* buff, char* buffEnd, const void* data, int len);
/* tries to add a formatted string to a bounded buffer */
char* buff_add (char* buff, char* buffEnd, const char* format, ... );
/* convenience macro used to define a bounded buffer, as well as
* a 'cursor' and 'end' variables all in one go.
*
* note: this doesn't place an initial terminating zero in the buffer,
* you need to use one of the buff_ functions for this. or simply
* do _cursor[0] = 0 manually.
*/
#define BUFF_DECL(_buff,_cursor,_end,_size) \
char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
#endif /* _ADB_UTILS_H */
+32
View File
@@ -40,6 +40,10 @@
#include "ui.h"
#include "screen_ui.h"
#include "device.h"
#include "adb_install.h"
extern "C" {
#include "minadbd/adb.h"
}
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 's' },
@@ -725,6 +729,21 @@ prompt_and_wait(Device* device) {
}
}
break;
case Device::APPLY_ADB_SIDELOAD:
ensure_path_mounted(CACHE_ROOT);
status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
if (status >= 0) {
if (status != INSTALL_SUCCESS) {
ui->SetBackground(RecoveryUI::ERROR);
ui->Print("Installation aborted.\n");
} else if (!ui->IsTextVisible()) {
return; // reboot if logs aren't visible
} else {
ui->Print("\nInstall from ADB complete.\n");
}
}
break;
}
}
}
@@ -741,6 +760,19 @@ main(int argc, char **argv) {
// If these fail, there's not really anywhere to complain...
freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
// If this binary is started with the single argument "--adbd",
// instead of being the normal recovery binary, it turns into kind
// of a stripped-down version of adbd that only supports the
// 'sideload' command. Note this must be a real argument, not
// anything in the command file or bootloader control block; the
// only way recovery should be run with this argument is when it
// starts a copy of itself from the apply_from_adb() function.
if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
adb_main();
return 0;
}
printf("Starting recovery on %s", ctime(&start));
Device* device = make_device();