mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-21 03:55:05 +00:00
Merge 02fc377e95
into 431c9ee33b
This commit is contained in:
commit
79e003ac18
9 changed files with 293 additions and 13 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "abstractcat"]
|
||||
path = abstractcat
|
||||
url = https://github.com/excitoon/abstractcat
|
1
abstractcat
Submodule
1
abstractcat
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit f232a5a7d590089721c64b5257198064bdf9fab7
|
|
@ -651,6 +651,8 @@ guess_record_format(const char *filename) {
|
|||
#define OPT_DISABLE_SCREENSAVER 1020
|
||||
#define OPT_SHORTCUT_MOD 1021
|
||||
#define OPT_NO_KEY_REPEAT 1022
|
||||
#define OPT_USE_SSH 1024
|
||||
#define OPT_SSH_ENDPOINT 1025
|
||||
|
||||
bool
|
||||
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||
|
@ -686,6 +688,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||
{"serial", required_argument, NULL, 's'},
|
||||
{"shortcut-mod", required_argument, NULL, OPT_SHORTCUT_MOD},
|
||||
{"show-touches", no_argument, NULL, 't'},
|
||||
{"ssh-endpoint", required_argument, NULL, OPT_SSH_ENDPOINT},
|
||||
{"stay-awake", no_argument, NULL, 'w'},
|
||||
{"turn-screen-off", no_argument, NULL, 'S'},
|
||||
{"verbosity", required_argument, NULL, 'V'},
|
||||
|
@ -697,6 +700,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||
{"window-height", required_argument, NULL, OPT_WINDOW_HEIGHT},
|
||||
{"window-borderless", no_argument, NULL,
|
||||
OPT_WINDOW_BORDERLESS},
|
||||
{"use-ssh", no_argument, NULL, OPT_USE_SSH},
|
||||
{NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
|
@ -799,6 +803,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||
case OPT_WINDOW_TITLE:
|
||||
opts->window_title = optarg;
|
||||
break;
|
||||
case OPT_SSH_ENDPOINT:
|
||||
opts->ssh_endpoint = optarg;
|
||||
break;
|
||||
case OPT_WINDOW_X:
|
||||
if (!parse_window_position(optarg, &opts->window_x)) {
|
||||
return false;
|
||||
|
@ -856,6 +863,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case OPT_USE_SSH:
|
||||
opts->use_ssh = true;
|
||||
break;
|
||||
default:
|
||||
// getopt prints the error message on stderr
|
||||
return false;
|
||||
|
|
|
@ -102,6 +102,49 @@ show_adb_err_msg(enum process_result err, const char *const argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
process_t
|
||||
scp_execute(const char *const scp_cmd[], size_t len) {
|
||||
const char *cmd[len + 2];
|
||||
unsigned i = 0;
|
||||
process_t process;
|
||||
|
||||
cmd[i++] = "scp";
|
||||
memcpy(&cmd[i], scp_cmd, len * sizeof(const char *));
|
||||
i += len;
|
||||
cmd[i] = NULL;
|
||||
enum process_result r = cmd_execute(cmd, &process);
|
||||
if (r != PROCESS_SUCCESS) {
|
||||
show_adb_err_msg(r, cmd);
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
return process;
|
||||
}
|
||||
|
||||
process_t
|
||||
ssh_execute(const char *endpoint, const char *const ssh_cmd[], size_t len,
|
||||
const char *const prefix_cmd[], size_t prefix_cmd_len,
|
||||
const char *const ssh_options[], size_t ssh_options_len) {
|
||||
const char *cmd[len + prefix_cmd_len + ssh_options_len + 3];
|
||||
unsigned i = 0;
|
||||
process_t process;
|
||||
|
||||
cmd[i++] = "ssh";
|
||||
memcpy(&cmd[i], ssh_options, ssh_options_len * sizeof(const char *));
|
||||
i += ssh_options_len;
|
||||
cmd[i++] = endpoint;
|
||||
memcpy(&cmd[i], prefix_cmd, prefix_cmd_len * sizeof(const char *));
|
||||
i += prefix_cmd_len;
|
||||
memcpy(&cmd[i], ssh_cmd, len * sizeof(const char *));
|
||||
i += len;
|
||||
cmd[i] = NULL;
|
||||
enum process_result r = cmd_execute(cmd, &process);
|
||||
if (r != PROCESS_SUCCESS) {
|
||||
show_adb_err_msg(r, cmd);
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
return process;
|
||||
}
|
||||
|
||||
process_t
|
||||
adb_execute(const char *serial, const char *const adb_cmd[], size_t len) {
|
||||
const char *cmd[len + 4];
|
||||
|
@ -164,6 +207,38 @@ adb_reverse_remove(const char *serial, const char *device_socket_name) {
|
|||
return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd));
|
||||
}
|
||||
|
||||
process_t
|
||||
ssh_push(const char *endpoint, const char *local, const char *remote) {
|
||||
#ifdef __WINDOWS__
|
||||
// Windows will parse the string, so the paths must be quoted
|
||||
// (see sys/win/command.c)
|
||||
local = strquote(local);
|
||||
if (!local) {
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
remote = strquote(remote);
|
||||
if (!remote) {
|
||||
SDL_free((void *) local);
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
char * destination = (char *) SDL_malloc(strlen(remote) + strlen(endpoint) + 2);
|
||||
strcpy(destination, endpoint);
|
||||
strcat(destination, ":");
|
||||
strcat(destination, remote);
|
||||
const char *const scp_cmd[] = {local, destination};
|
||||
process_t proc = scp_execute(scp_cmd, ARRAY_LEN(scp_cmd));
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
SDL_free((void *) remote);
|
||||
SDL_free((void *) local);
|
||||
#endif
|
||||
SDL_free((void *) destination);
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
process_t
|
||||
adb_push(const char *serial, const char *local, const char *remote) {
|
||||
#ifdef __WINDOWS__
|
||||
|
|
|
@ -57,6 +57,14 @@ cmd_terminate(process_t pid);
|
|||
bool
|
||||
cmd_simple_wait(process_t pid, exit_code_t *exit_code);
|
||||
|
||||
process_t
|
||||
scp_execute(const char *const ssh_cmd[], size_t len);
|
||||
|
||||
process_t
|
||||
ssh_execute(const char *endpoint, const char *const ssh_cmd[], size_t len,
|
||||
const char *const prefix_cmd[], size_t prefix_cmd_len,
|
||||
const char *const ssh_options[], size_t ssh_options_len);
|
||||
|
||||
process_t
|
||||
adb_execute(const char *serial, const char *const adb_cmd[], size_t len);
|
||||
|
||||
|
@ -74,6 +82,9 @@ adb_reverse(const char *serial, const char *device_socket_name,
|
|||
process_t
|
||||
adb_reverse_remove(const char *serial, const char *device_socket_name);
|
||||
|
||||
process_t
|
||||
ssh_push(const char *endpoint, const char *local, const char *remote);
|
||||
|
||||
process_t
|
||||
adb_push(const char *serial, const char *local, const char *remote);
|
||||
|
||||
|
|
|
@ -319,6 +319,8 @@ scrcpy(const struct scrcpy_options *options) {
|
|||
.stay_awake = options->stay_awake,
|
||||
.codec_options = options->codec_options,
|
||||
.force_adb_forward = options->force_adb_forward,
|
||||
.use_ssh = options->use_ssh,
|
||||
.ssh_endpoint = options->ssh_endpoint,
|
||||
};
|
||||
if (!server_start(&server, options->serial, ¶ms)) {
|
||||
return false;
|
||||
|
|
|
@ -51,6 +51,7 @@ struct scrcpy_options {
|
|||
const char *push_target;
|
||||
const char *render_driver;
|
||||
const char *codec_options;
|
||||
const char *ssh_endpoint;
|
||||
enum sc_log_level log_level;
|
||||
enum sc_record_format record_format;
|
||||
struct sc_port_range port_range;
|
||||
|
@ -79,6 +80,7 @@ struct scrcpy_options {
|
|||
bool force_adb_forward;
|
||||
bool disable_screensaver;
|
||||
bool forward_key_repeat;
|
||||
bool use_ssh;
|
||||
};
|
||||
|
||||
#define SCRCPY_OPTIONS_DEFAULT { \
|
||||
|
@ -123,6 +125,8 @@ struct scrcpy_options {
|
|||
.force_adb_forward = false, \
|
||||
.disable_screensaver = false, \
|
||||
.forward_key_repeat = true, \
|
||||
.use_ssh = false, \
|
||||
.ssh_endpoint = NULL, \
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
196
app/src/server.c
196
app/src/server.c
|
@ -16,11 +16,18 @@
|
|||
#include "util/str_util.h"
|
||||
|
||||
#define SOCKET_NAME "scrcpy"
|
||||
#define SSH_SOCKET_NAME "/dev/socket/scrcpy"
|
||||
#define SERVER_FILENAME "scrcpy-server"
|
||||
#define ABSTRACTCAT_FILENAME "abstractcat"
|
||||
|
||||
#define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
|
||||
#define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
||||
|
||||
#define DEFAULT_ABSTRACTCAT_PATH PREFIX "/share/scrcpy/" ABSTRACTCAT_FILENAME
|
||||
#define DEVICE_ABSTRACTCAT_PATH "/data/local/tmp/" ABSTRACTCAT_FILENAME
|
||||
|
||||
static void close_socket(socket_t socket);
|
||||
|
||||
static char *
|
||||
get_server_path(void) {
|
||||
#ifdef __WINDOWS__
|
||||
|
@ -87,8 +94,90 @@ get_server_path(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static char *
|
||||
get_abstractcat_path(void) {
|
||||
#ifdef __WINDOWS__
|
||||
const wchar_t *abstractcat_path_env = _wgetenv(L"SCRCPY_ABSTRACTCAT_PATH");
|
||||
#else
|
||||
const char *abstractcat_path_env = getenv("SCRCPY_ABSTRACTCAT_PATH");
|
||||
#endif
|
||||
if (abstractcat_path_env) {
|
||||
// if the envvar is set, use it
|
||||
#ifdef __WINDOWS__
|
||||
char *abstractcat_path = utf8_from_wide_char(abstractcat_path_env);
|
||||
#else
|
||||
char *abstractcat_path = SDL_strdup(abstractcat_path_env);
|
||||
#endif
|
||||
if (!abstractcat_path) {
|
||||
LOGE("Could not allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
LOGD("Using SCRCPY_ABSTRACTCAT_PATH: %s", abstractcat_path);
|
||||
return abstractcat_path;
|
||||
}
|
||||
|
||||
#ifndef PORTABLE
|
||||
LOGD("Using abstractcat: " DEFAULT_ABSTRACTCAT_PATH);
|
||||
char *abstractcat_path = SDL_strdup(DEFAULT_ABSTRACTCAT_PATH);
|
||||
if (!abstractcat_path) {
|
||||
LOGE("Could not allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
// the absolute path is hardcoded
|
||||
return abstractcat_path;
|
||||
#else
|
||||
|
||||
// use scrcpy-server in the same directory as the executable
|
||||
char *executable_path = get_executable_path();
|
||||
if (!executable_path) {
|
||||
LOGE("Could not get executable path, "
|
||||
"using " ABSTRACTCAT_FILENAME " from current directory");
|
||||
// not found, use current directory
|
||||
return ABSTRACTCAT_FILENAME;
|
||||
}
|
||||
char *dir = dirname(executable_path);
|
||||
size_t dirlen = strlen(dir);
|
||||
|
||||
// sizeof(ABSTRACTCAT_FILENAME) gives statically the size including the null byte
|
||||
size_t len = dirlen + 1 + sizeof(ABSTRACTCAT_FILENAME);
|
||||
char *abstractcat_path = SDL_malloc(len);
|
||||
if (!abstractcat_path) {
|
||||
LOGE("Could not alloc abstractcat path string, "
|
||||
"using " ABSTRACTCAT_FILENAME " from current directory");
|
||||
SDL_free(executable_path);
|
||||
return ABSTRACTCAT_FILENAME;
|
||||
}
|
||||
|
||||
memcpy(abstractcat_path, dir, dirlen);
|
||||
abstractcat_path[dirlen] = PATH_SEPARATOR;
|
||||
memcpy(&abstractcat_path[dirlen + 1], ABSTRACTCAT_FILENAME, sizeof(ABSTRACTCAT_FILENAME));
|
||||
// the final null byte has been copied with ABSTRACTCAT_FILENAME
|
||||
|
||||
SDL_free(executable_path);
|
||||
|
||||
LOGD("Using abstractcat (portable): %s", abstractcat_path);
|
||||
return abstractcat_path;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
push_server(const char *serial) {
|
||||
push_abstractcat(const struct server_params *params) {
|
||||
char *abstractcat_path = get_abstractcat_path();
|
||||
if (!abstractcat_path) {
|
||||
return false;
|
||||
}
|
||||
if (!is_regular_file(abstractcat_path)) {
|
||||
LOGE("'%s' does not exist or is not a regular file\n", abstractcat_path);
|
||||
SDL_free(abstractcat_path);
|
||||
return false;
|
||||
}
|
||||
process_t process = ssh_push(params->ssh_endpoint, abstractcat_path, DEVICE_ABSTRACTCAT_PATH);
|
||||
SDL_free(abstractcat_path);
|
||||
return process_check_success(process, "scp");
|
||||
}
|
||||
|
||||
static bool
|
||||
push_server(const char *serial, const struct server_params *params) {
|
||||
char *server_path = get_server_path();
|
||||
if (!server_path) {
|
||||
return false;
|
||||
|
@ -98,11 +187,26 @@ push_server(const char *serial) {
|
|||
SDL_free(server_path);
|
||||
return false;
|
||||
}
|
||||
process_t process = adb_push(serial, server_path, DEVICE_SERVER_PATH);
|
||||
process_t process;
|
||||
if (params->use_ssh)
|
||||
process = ssh_push(params->ssh_endpoint, server_path, DEVICE_SERVER_PATH);
|
||||
else
|
||||
process = adb_push(serial, server_path, DEVICE_SERVER_PATH);
|
||||
SDL_free(server_path);
|
||||
return process_check_success(process, "adb push");
|
||||
}
|
||||
|
||||
static bool prepare_ssh_socket_path(const struct server_params *params) {
|
||||
const char *const cmd[] = {
|
||||
"rm",
|
||||
"-f",
|
||||
SSH_SOCKET_NAME,
|
||||
};
|
||||
process_t process = ssh_execute(params->ssh_endpoint, cmd, sizeof(cmd) / sizeof(cmd[0]),
|
||||
NULL, 0, NULL, 0);
|
||||
return process_check_success(process, "ssh rm -f " SSH_SOCKET_NAME);
|
||||
}
|
||||
|
||||
static bool
|
||||
enable_tunnel_reverse(const char *serial, uint16_t local_port) {
|
||||
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
|
||||
|
@ -264,9 +368,9 @@ execute_server(struct server *server, const struct server_params *params) {
|
|||
sprintf(lock_video_orientation_string, "%"PRIi8, params->lock_video_orientation);
|
||||
sprintf(display_id_string, "%"PRIu16, params->display_id);
|
||||
const char *const cmd[] = {
|
||||
"shell",
|
||||
params->use_ssh ? "ANDROID_DATA=/data" : "shell",
|
||||
"CLASSPATH=" DEVICE_SERVER_PATH,
|
||||
"app_process",
|
||||
"/system/bin/app_process",
|
||||
#ifdef SERVER_DEBUGGER
|
||||
# define SERVER_DEBUGGER_PORT "5005"
|
||||
# ifdef SERVER_DEBUGGER_METHOD_NEW
|
||||
|
@ -286,7 +390,7 @@ execute_server(struct server *server, const struct server_params *params) {
|
|||
bit_rate_string,
|
||||
max_fps_string,
|
||||
lock_video_orientation_string,
|
||||
server->tunnel_forward ? "true" : "false",
|
||||
server->tunnel_forward || params->force_adb_forward ? "true" : "false",
|
||||
params->crop ? params->crop : "-",
|
||||
"true", // always send frame meta (packet boundaries + timestamp)
|
||||
params->control ? "true" : "false",
|
||||
|
@ -306,7 +410,59 @@ execute_server(struct server *server, const struct server_params *params) {
|
|||
// Port: 5005
|
||||
// Then click on "Debug"
|
||||
#endif
|
||||
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
||||
if (params->use_ssh)
|
||||
{
|
||||
for (uint16_t port = server->port_range.first;;) {
|
||||
server->server_socket = listen_on_port(port);
|
||||
if (server->server_socket == INVALID_SOCKET) {
|
||||
if (port < server->port_range.last) {
|
||||
LOGW("Could not listen on port %" PRIu16", retrying on %" PRIu16,
|
||||
port, (uint16_t) (port + 1));
|
||||
port++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (server->port_range.first == server->port_range.last) {
|
||||
LOGE("Could not listen on port %" PRIu16, server->port_range.first);
|
||||
} else {
|
||||
LOGE("Could not listen on any port in range %" PRIu16 ":%" PRIu16,
|
||||
server->port_range.first, server->port_range.last);
|
||||
}
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
server->local_port = port;
|
||||
char *tunnel_desc = SDL_strdup(SSH_SOCKET_NAME ":localhost:12345");
|
||||
|
||||
if (params->force_adb_forward)
|
||||
sprintf(tunnel_desc, "localhost:%d:" SSH_SOCKET_NAME, port);
|
||||
else
|
||||
sprintf(tunnel_desc, SSH_SOCKET_NAME ":localhost:%d", port);
|
||||
|
||||
const char *const ssh_options[] = {
|
||||
"-o", "ExitOnForwardFailure=yes",
|
||||
params->force_adb_forward ? "-L" : "-R", tunnel_desc,
|
||||
};
|
||||
|
||||
const char *const prefix_cmd[] = {
|
||||
DEVICE_ABSTRACTCAT_PATH,
|
||||
params->force_adb_forward ? SSH_SOCKET_NAME : "@" SOCKET_NAME, // Source.
|
||||
params->force_adb_forward ? "@" SOCKET_NAME : SSH_SOCKET_NAME, // Destination.
|
||||
"2", // Maximum connections to forward.
|
||||
};
|
||||
|
||||
if (params->force_adb_forward) {
|
||||
close_socket(server->server_socket);
|
||||
server->server_socket = INVALID_SOCKET;
|
||||
server->tunnel_forward = true;
|
||||
}
|
||||
|
||||
return ssh_execute(params->ssh_endpoint, cmd, sizeof(cmd) / sizeof(cmd[0]),
|
||||
prefix_cmd, sizeof(prefix_cmd) / sizeof(prefix_cmd[0]),
|
||||
ssh_options, sizeof(ssh_options) / sizeof(ssh_options[0]));
|
||||
}
|
||||
}
|
||||
else
|
||||
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
||||
}
|
||||
|
||||
static socket_t
|
||||
|
@ -385,11 +541,19 @@ server_start(struct server *server, const char *serial,
|
|||
}
|
||||
}
|
||||
|
||||
if (!push_server(serial)) {
|
||||
server->use_ssh = params->use_ssh;
|
||||
|
||||
if (!push_server(serial, params)) {
|
||||
goto error1;
|
||||
}
|
||||
|
||||
if (!enable_tunnel_any_port(server, params->port_range,
|
||||
if (params->use_ssh && !push_abstractcat(params))
|
||||
goto error1;
|
||||
|
||||
if (params->use_ssh && !prepare_ssh_socket_path(params))
|
||||
goto error1;
|
||||
|
||||
if (!params->use_ssh && !enable_tunnel_any_port(server, params->port_range,
|
||||
params->force_adb_forward)) {
|
||||
goto error1;
|
||||
}
|
||||
|
@ -427,7 +591,10 @@ error2:
|
|||
(void) was_closed;
|
||||
close_socket(server->server_socket);
|
||||
}
|
||||
disable_tunnel(server);
|
||||
|
||||
if (!server->use_ssh) {
|
||||
disable_tunnel(server);
|
||||
}
|
||||
error1:
|
||||
SDL_free(server->serial);
|
||||
return false;
|
||||
|
@ -470,9 +637,12 @@ server_connect_to(struct server *server) {
|
|||
}
|
||||
}
|
||||
|
||||
// we don't need the adb tunnel anymore
|
||||
disable_tunnel(server); // ignore failure
|
||||
server->tunnel_enabled = false;
|
||||
if (server->tunnel_enabled) {
|
||||
// we don't need the adb tunnel anymore
|
||||
if (!server->use_ssh)
|
||||
disable_tunnel(server); // ignore failure
|
||||
server->tunnel_enabled = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -494,7 +664,7 @@ server_stop(struct server *server) {
|
|||
|
||||
cmd_terminate(server->process);
|
||||
|
||||
if (server->tunnel_enabled) {
|
||||
if (server->tunnel_enabled && !server->use_ssh) {
|
||||
// ignore failure
|
||||
disable_tunnel(server);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ struct server {
|
|||
uint16_t local_port; // selected from port_range
|
||||
bool tunnel_enabled;
|
||||
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
||||
bool use_ssh;
|
||||
};
|
||||
|
||||
#define SERVER_INITIALIZER { \
|
||||
|
@ -42,12 +43,14 @@ struct server {
|
|||
.local_port = 0, \
|
||||
.tunnel_enabled = false, \
|
||||
.tunnel_forward = false, \
|
||||
.use_ssh = false, \
|
||||
}
|
||||
|
||||
struct server_params {
|
||||
enum sc_log_level log_level;
|
||||
const char *crop;
|
||||
const char *codec_options;
|
||||
const char *ssh_endpoint;
|
||||
struct sc_port_range port_range;
|
||||
uint16_t max_size;
|
||||
uint32_t bit_rate;
|
||||
|
@ -58,6 +61,7 @@ struct server_params {
|
|||
bool show_touches;
|
||||
bool stay_awake;
|
||||
bool force_adb_forward;
|
||||
bool use_ssh;
|
||||
};
|
||||
|
||||
// init default values
|
||||
|
|
Loading…
Add table
Reference in a new issue