Skip to content

Commit

Permalink
Build libadb staticlib
Browse files Browse the repository at this point in the history
  • Loading branch information
wsvn53 committed May 31, 2022
1 parent 4a7bf16 commit 2d21e4b
Show file tree
Hide file tree
Showing 23 changed files with 945 additions and 3 deletions.
6 changes: 6 additions & 0 deletions porting/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ protobuf: protobuf/iphoneos/arm64 protobuf/iphonesimulator/x86_64
protobuf/%:
@echo "|-> Making $@ ..."
TARGET=$@ OUTPUT=../output bash ./scripts/make-protobuf.sh

## adb
adb: adb/iphoneos/arm64 adb/iphonesimulator/x86_64
adb/%:
@echo "|-> Making $@ ..."
TARGET=$@ OUTPUT=../output bash ./scripts/make-adb.sh
86 changes: 86 additions & 0 deletions porting/adb/adb.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* adb.cpp is used to replace original adb.cpp
*/

#include <stdio.h>
#include <pthread.h>

#define launch_server(...) launch_server_unused(__VA_ARGS__)
#include "adb/adb.cpp"
#undef launch_server

void fdevent_reset_porting(void);
void clear_listener_list(void);
void clear_transport_list(void);

// replace exit to pthread_exit
void exit(int code) {
pthread_exit(0);
}

void launch_server_main(int pipe_write, const char *thread_socket_spec) {
// Launch server with pipe
fcntl(pipe_write, F_SETFD, 0);
printf("launch_server_main: %d\n", pipe_write);

// We don't need to do clear or reset at first time
static bool not_first = false;
if (not_first == true) {
clear_listener_list();
clear_transport_list();
fdevent_reset_porting();
}
not_first = true;

#ifdef __ANDROID__
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);
printf("fdsan_error_level: %d\n", android_fdsan_get_error_level());
#endif

// Start main server
adb_server_main(false, thread_socket_spec, pipe_write);
}

int launch_server(const std::string& socket_spec) {
static char *thread_socket_spec;
static int pipe_server[2];

printf("socket %s\n", socket_spec.c_str());
thread_socket_spec = strdup(socket_spec.c_str());

// Reset last used pipe
pipe(pipe_server);

// set up a pipe so the child can tell us when it is ready.
if (pipe_server[0] < 0 || pipe_server[1] < 0) {
fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
return -1;
}

std::string path = android::base::GetExecutablePath();

// launch server in new thread
std::thread adb_thread([]() {
launch_server_main(pipe_server[1], thread_socket_spec);
});
adb_thread.detach();

// parent side
printf("launch_server pipe_write: %d\n", pipe_server[0]);
printf("launch_server pipe_read: %d\n", pipe_server[1]);

// wait for the "OK\n" message from the child
char temp[3] = {};
int ret = adb_read(pipe_server[0], temp, 3);
int saved_errno = errno;
if (ret < 0) {
fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
return -1;
}
if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
ReportServerStartupFailure(0);
return -1;
}

return 0;
}
41 changes: 41 additions & 0 deletions porting/adb/adb_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* adb_client.cpp used to fix adb_set_socket_spec function
*/

extern "C" {
bool adb_kill_server_porting(void);
}

#define adb_set_socket_spec(...) adb_set_socket_spec_unused(__VA_ARGS__)
#define adb_check_server_version(...) adb_check_server_version_unused(__VA_ARGS__)

#include "adb/client/adb_client.cpp"

#undef adb_set_socket_spec
#undef adb_check_server_version

bool adb_check_server_version(std::string* _Nonnull error) {
// If this is first time be called, ignore, because __adb_server_socket_spec not ready
static bool first_call = true;
if (first_call) {
first_call = false;
return true;
}

// Make adb check server version can be called more than once
static std::once_flag once;
static bool result;
static std::string* err;
err = new std::string();
result = __adb_check_server_version(err);
*error = *err;
return result;
}

void adb_set_socket_spec(const char* socket_spec) {
if (__adb_server_socket_spec) {
// prevent fatal error here, just return
return;
}
__adb_server_socket_spec = socket_spec;
}
97 changes: 97 additions & 0 deletions porting/adb/adb_io.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* adb_io.cpp is used to handle ReadExactly with select which can be used to control thread exit
*/

#define ReadFdExactly(...) ReadFdExactly_unused(__VA_ARGS__)

#include "adb/adb_io.cpp"

#undef ReadFdExactly
#undef read

// return bool to indicated whether continue to read
bool read_select(borrowed_fd fd) {
char name[10];
memset(name, 0, sizeof(name));
pthread_getname_np(pthread_self(), name, sizeof(name));
if (strlen(name) == 0) {
return true;
}

std::string thread_name = name;
// thread_name split by ':'
size_t prefix_pos = thread_name.find("adb:");
if (prefix_pos == std::string::npos) {
// not prefix with 'adb:', continue to read with adb_read
return true;
}

// split fds
thread_name.erase(0,4);
std::string thread_fd_str = thread_name.substr(0, thread_name.find(":"));
int thread_fd = atoi(thread_fd_str.c_str());
if (thread_fd <= 0) return true;

// select read fds
// fd_set with select
fd_set fds;
FD_ZERO(&fds);
FD_SET(thread_fd, &fds);
FD_SET(fd.get(), &fds);

while (1) {
int ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
if (ret == 0) {
continue;
}

if (FD_ISSET(thread_fd, &fds)) {
char thread_cmd;
size_t n = read(thread_fd, &thread_cmd, 1);
if (n > 0 && thread_cmd == 'Q') {
pthread_exit((void *)0);
return false;
}
printf("unknown thread command: %c\n", thread_cmd);
}

if (FD_ISSET(fd.get(), &fds)) {
return true;
}
}

return false;
}

bool ReadFdExactly(borrowed_fd fd, void* buf, size_t len) {
char* p = reinterpret_cast<char*>(buf);

size_t len0 = len;

D("readx: fd=%d wanted=%zu", fd.get(), len);
while (len > 0) {
if (!read_select(fd)) {
return false;
}

int r = adb_read(fd, p, len);
if (r > 0) {
len -= r;
p += r;
} else if (r == -1) {
D("readx: fd=%d error %d: %s", fd.get(), errno, strerror(errno));
return false;
} else {
D("readx: fd=%d disconnected", fd.get());
errno = 0;
return false;
}
}

VLOG(RWX) << "readx: fd=" << fd.get() << " wanted=" << len0 << " got=" << (len0 - len) << " "
<< dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);

return true;
}


9 changes: 9 additions & 0 deletions porting/adb/adb_listeners.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* adb_listeners.cpp used to modify source code of adb_listeners.cpp in android_tools
*/

#include "adb/adb_listeners.cpp"

void clear_listener_list() {
listener_list.clear();
}
40 changes: 40 additions & 0 deletions porting/adb/adb_porting.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* adb_porting.cpp used to define some functions to c
*/
#include <stdio.h>
#include <stdarg.h>
#include "adb_trace.h"

int porting_log_print(int p, const char *tag, const char *fmt, ...) {
va_list args_list;
va_start(args_list, fmt);
int ret = vprintf(fmt, args_list);
va_end(args_list);

return ret;
}

int porting_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...) {
va_list args_list;
va_start(args_list, fmt);
int ret = vprintf(fmt, args_list);
va_end(args_list);

return ret;
}

void usb_init() {
return;
}

void usb_cleanup() {
return;
}

void adb_trace_enable_porting(int trace_tag) {
adb_trace_enable((AdbTrace)trace_tag);
}

void abort() {
pthread_exit(NULL);
}
90 changes: 90 additions & 0 deletions porting/adb/commandline.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* commandline.cpp is use to handle command outputs
*/
#include <stdio.h>
#include <string.h>

int printf_hijack(const char *format, ...);
size_t fwrite_hijack(const void *__ptr, size_t __size, size_t __nitems, FILE *__stream);
int fprintf_hijack(FILE *file, const char *format, ...);

#define printf(...) printf_hijack(__VA_ARGS__)
#define fwrite(...) fwrite_hijack(__VA_ARGS__)
#define fprintf(...) fprintf_hijack(__VA_ARGS__)

#include "adb/client/commandline.cpp"
#include "adb/client/line_printer.cpp"

#undef printf
#undef fwrite

// Declare global variable to catch outputs
static std::string adb_commandline_stdout = "";
void append_commandline_stdout(char *text) {
static pthread_mutex_t adb_append_stdout_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&adb_append_stdout_lock);
adb_commandline_stdout.append(text);
pthread_mutex_unlock(&adb_append_stdout_lock);
}

extern "C" {
int adb_commandline_porting(int argc, const char** argv, char **message);
}

bool adb_check_server_version(std::string* _Nonnull error);
int adb_commandline_porting(int argc, const char** argv, char **message) {
// Empty stdout handler
adb_commandline_stdout = "";

// Trigger adb_check_server_version once before adb_connect
// Because adb_check_server_version only be called once, hacked here
static std::string *error;
error = new std::string();
if (!adb_check_server_version(error)) {
*message = strdup(error->c_str());
return -1;
}

// Execute adb commandline
int ret = adb_commandline(argc, argv);
*message = strdup(adb_commandline_stdout.c_str());
if (ret != 0 && strlen(*message) == 0) {
*message = strdup("adb_commandline failed");
}
return ret;
}

int printf_hijack(const char *format, ...) {
va_list args;
va_start(args, format);
int size = vsnprintf(NULL, 0, format, args);
char text[size+1];
vsprintf(text, format, args);
text[size] = '\0';
va_end(args);
append_commandline_stdout(text);
return 0;
}

size_t fwrite_hijack(const void *__ptr, size_t __size, size_t __nitems, FILE *__stream) {
if (__ptr == NULL || strlen((char *)__ptr) == 0) {
return 0;
}
char text[__nitems+1];
strncpy(text, (char *)__ptr, __nitems);
text[__nitems] = '\0';
append_commandline_stdout(text);
return 0;
}

int fprintf_hijack(FILE *file, const char *format, ...) {
va_list args;
va_start(args, format);
int size = vsnprintf(NULL, 0, format, args);
char text[size+1];
vsprintf(text, format, args);
text[size] = '\0';
va_end(args);
append_commandline_stdout(text);
return 0;
}
Loading

0 comments on commit 2d21e4b

Please sign in to comment.