Compare commits
2 Commits
install.8
...
build-deps
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
652e210bfb | ||
|
|
a1117c58ac |
2
app/deps/.gitignore
vendored
Normal file
2
app/deps/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/data
|
||||||
|
/target-*
|
||||||
64
app/deps/src/build-ffmpeg.sh
Executable file
64
app/deps/src/build-ffmpeg.sh
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
. init_deps
|
||||||
|
|
||||||
|
VERSION=5.0.1
|
||||||
|
FILENAME=ffmpeg-$VERSION.tar.xz
|
||||||
|
|
||||||
|
URL=http://ffmpeg.org/releases/ffmpeg-$VERSION.tar.xz
|
||||||
|
SHA256SUM=ef2efae259ce80a240de48ec85ecb062cecca26e4352ffb3fda562c21a93007b
|
||||||
|
|
||||||
|
DEP_DIR="$DATA_DIR/ffmpeg-$VERSION-$SHA256SUM"
|
||||||
|
|
||||||
|
if [[ ! -d "$DEP_DIR" ]]
|
||||||
|
then
|
||||||
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
|
|
||||||
|
mkdir "$DEP_DIR"
|
||||||
|
cd "$DEP_DIR"
|
||||||
|
|
||||||
|
tar xvf "../$FILENAME"
|
||||||
|
else
|
||||||
|
echo "$DEP_DIR found"
|
||||||
|
cd "$DEP_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "ffmpeg-$VERSION"
|
||||||
|
rm -rf "build-$HOST"
|
||||||
|
mkdir "build-$HOST"
|
||||||
|
cd "build-$HOST"
|
||||||
|
|
||||||
|
params=(
|
||||||
|
--prefix="$INSTALL_DIR"
|
||||||
|
--arch="$ARCH"
|
||||||
|
--disable-autodetect
|
||||||
|
--disable-programs
|
||||||
|
--disable-everything
|
||||||
|
--disable-doc
|
||||||
|
--disable-swresample
|
||||||
|
--disable-swscale
|
||||||
|
--disable-avfilter
|
||||||
|
--disable-postproc
|
||||||
|
--disable-static
|
||||||
|
--enable-shared
|
||||||
|
--enable-decoder=h264
|
||||||
|
--enable-decoder=png
|
||||||
|
--enable-muxer=mp4
|
||||||
|
--enable-muxer=matroska
|
||||||
|
)
|
||||||
|
|
||||||
|
case "$HOST_SYSTEM" in
|
||||||
|
linux)
|
||||||
|
params+=(--enable-libv4l2)
|
||||||
|
;;
|
||||||
|
windows)
|
||||||
|
params+=(--target-os=mingw32)
|
||||||
|
params+=(--cross-prefix="$HOST-")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fail "Unsupported platform: $HOST"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
../configure "${params[@]}"
|
||||||
|
make -j $NJOBS
|
||||||
|
make install
|
||||||
56
app/deps/src/init_deps
Normal file
56
app/deps/src/init_deps
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
set -e
|
||||||
|
|
||||||
|
# The caller must set the following environment variable
|
||||||
|
# - $HOST (e.g. "x86_64-linux-gnu")
|
||||||
|
# - $HOST_SYSTEM ("linux", "windows", "apple"), for scripts convenience
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -z "$HOST" ]] && fail '$HOST not defined'
|
||||||
|
|
||||||
|
if [[ "$HOST" == *linux* ]]
|
||||||
|
then
|
||||||
|
HOST_SYSTEM='linux'
|
||||||
|
elif [[ "$HOST" == *mingw* ]]
|
||||||
|
then
|
||||||
|
HOST_SYSTEM='windows'
|
||||||
|
else
|
||||||
|
fail "Host system could not be deduced from '$HOST'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARCH="${HOST%%-*}"
|
||||||
|
[[ -z "$ARCH" ]] && fail "Arch could not be deduced from '$HOST'"
|
||||||
|
|
||||||
|
DIR=$(dirname ${BASH_SOURCE[0]})
|
||||||
|
cd "$DIR"
|
||||||
|
|
||||||
|
DATA_DIR=$(realpath ../data)
|
||||||
|
INSTALL_DIR=$(realpath ../target-"$HOST")
|
||||||
|
NJOBS=$(grep -c ^processor /proc/cpuinfo)
|
||||||
|
|
||||||
|
mkdir -p "$DATA_DIR"
|
||||||
|
cd "$DATA_DIR"
|
||||||
|
|
||||||
|
checksum() {
|
||||||
|
local file="$1"
|
||||||
|
local sum="$2"
|
||||||
|
echo "$file: verifying checksum..."
|
||||||
|
echo "$sum $file" | sha256sum -c
|
||||||
|
}
|
||||||
|
|
||||||
|
get_file() {
|
||||||
|
local url="$1"
|
||||||
|
local file="$2"
|
||||||
|
local sum="$3"
|
||||||
|
if [[ -f "$file" ]]
|
||||||
|
then
|
||||||
|
echo "$file: found"
|
||||||
|
else
|
||||||
|
echo "$file: not found, downloading..."
|
||||||
|
wget "$url" -O "$file"
|
||||||
|
fi
|
||||||
|
checksum "$file" "$sum"
|
||||||
|
}
|
||||||
@@ -188,7 +188,7 @@ conf.set_quoted('SCRCPY_VERSION', meson.project_version())
|
|||||||
# the prefix used during configuration (meson --prefix=PREFIX)
|
# the prefix used during configuration (meson --prefix=PREFIX)
|
||||||
conf.set_quoted('PREFIX', get_option('prefix'))
|
conf.set_quoted('PREFIX', get_option('prefix'))
|
||||||
|
|
||||||
# build a "portable" version (with scrcpy-server.apk accessible from the same
|
# build a "portable" version (with scrcpy-server accessible from the same
|
||||||
# directory as the executable)
|
# directory as the executable)
|
||||||
conf.set('PORTABLE', get_option('portable'))
|
conf.set('PORTABLE', get_option('portable'))
|
||||||
|
|
||||||
|
|||||||
@@ -329,17 +329,6 @@ sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
|
|||||||
return process_check_success_intr(intr, pid, "adb install", flags);
|
return process_check_success_intr(intr, pid, "adb install", flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
sc_adb_uninstall(struct sc_intr *intr, const char *serial, const char *pkg,
|
|
||||||
unsigned flags) {
|
|
||||||
assert(serial);
|
|
||||||
const char *const argv[] =
|
|
||||||
SC_ADB_COMMAND("-s", serial, "uninstall", pkg);
|
|
||||||
|
|
||||||
sc_pid pid = sc_adb_execute(argv, flags);
|
|
||||||
return process_check_success_intr(intr, pid, "adb uninstall", flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_adb_tcpip(struct sc_intr *intr, const char *serial, uint16_t port,
|
sc_adb_tcpip(struct sc_intr *intr, const char *serial, uint16_t port,
|
||||||
unsigned flags) {
|
unsigned flags) {
|
||||||
@@ -445,7 +434,6 @@ sc_adb_list_devices(struct sc_intr *intr, unsigned flags,
|
|||||||
"Please report an issue.");
|
"Please report an issue.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#undef BUFSIZE
|
|
||||||
|
|
||||||
// It is parsed as a NUL-terminated string
|
// It is parsed as a NUL-terminated string
|
||||||
buf[r] = '\0';
|
buf[r] = '\0';
|
||||||
@@ -722,101 +710,5 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
|
|||||||
// It is parsed as a NUL-terminated string
|
// It is parsed as a NUL-terminated string
|
||||||
buf[r] = '\0';
|
buf[r] = '\0';
|
||||||
|
|
||||||
return sc_adb_parse_device_ip(buf);
|
return sc_adb_parse_device_ip_from_output(buf);
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
sc_adb_get_installed_apk_path(struct sc_intr *intr, const char *serial,
|
|
||||||
unsigned flags) {
|
|
||||||
assert(serial);
|
|
||||||
const char *const argv[] =
|
|
||||||
SC_ADB_COMMAND("-s", serial, "shell", "pm", "list", "package", "-f",
|
|
||||||
SC_ANDROID_PACKAGE);
|
|
||||||
|
|
||||||
sc_pipe pout;
|
|
||||||
sc_pid pid = sc_adb_execute_p(argv, flags, &pout);
|
|
||||||
if (pid == SC_PROCESS_NONE) {
|
|
||||||
LOGD("Could not execute \"pm list packages\"");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "pm list packages -f <package>" output should contain only one line, so
|
|
||||||
// the output should be short
|
|
||||||
char buf[1024];
|
|
||||||
ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
|
|
||||||
sc_pipe_close(pout);
|
|
||||||
|
|
||||||
bool ok = process_check_success_intr(intr, pid, "pm list packages", flags);
|
|
||||||
if (!ok) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((size_t) r < sizeof(buf));
|
|
||||||
if (r == sizeof(buf) - 1) {
|
|
||||||
// The implementation assumes that the output of "pm list packages"
|
|
||||||
// fits in the buffer in a single pass
|
|
||||||
LOGW("Result of \"pm list package\" does not fit in 1Kb. "
|
|
||||||
"Please report an issue.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is parsed as a NUL-terminated string
|
|
||||||
buf[r] = '\0';
|
|
||||||
|
|
||||||
return sc_adb_parse_installed_apk_path(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
sc_adb_get_installed_apk_version(struct sc_intr *intr, const char *serial,
|
|
||||||
unsigned flags) {
|
|
||||||
assert(serial);
|
|
||||||
const char *const argv[] =
|
|
||||||
SC_ADB_COMMAND("-s", serial, "shell", "dumpsys", "package",
|
|
||||||
SC_ANDROID_PACKAGE);
|
|
||||||
|
|
||||||
sc_pipe pout;
|
|
||||||
sc_pid pid = sc_adb_execute_p(argv, flags, &pout);
|
|
||||||
if (pid == SC_PROCESS_NONE) {
|
|
||||||
LOGD("Could not execute \"dumpsys package\"");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "dumpsys package" output can be huge (e.g. 16k), but versionName is at
|
|
||||||
// the beginning, typically in the first 1024 bytes (64k should be enough
|
|
||||||
// for the whole output anyway)
|
|
||||||
#define BUFSIZE 65536
|
|
||||||
char *buf = malloc(BUFSIZE);
|
|
||||||
if (!buf) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, BUFSIZE - 1);
|
|
||||||
sc_pipe_close(pout);
|
|
||||||
|
|
||||||
bool ok = process_check_success_intr(intr, pid, "dumpsys package", flags);
|
|
||||||
if (!ok) {
|
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == -1) {
|
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((size_t) r < BUFSIZE);
|
|
||||||
#undef BUFSIZE
|
|
||||||
// if r == sizeof(buf), then the output is truncated, but we don't care,
|
|
||||||
// versionName is at the beginning in practice, and is unlikely to be
|
|
||||||
// truncated at 64k
|
|
||||||
|
|
||||||
// It is parsed as a NUL-terminated string
|
|
||||||
buf[r] = '\0';
|
|
||||||
|
|
||||||
char *version = sc_adb_parse_installed_apk_version(buf);
|
|
||||||
free(buf);
|
|
||||||
return version;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)
|
#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)
|
||||||
|
|
||||||
#define SC_ANDROID_PACKAGE "com.genymobile.scrcpy"
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
sc_adb_get_executable(void);
|
sc_adb_get_executable(void);
|
||||||
|
|
||||||
@@ -66,10 +64,6 @@ bool
|
|||||||
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
|
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
|
||||||
unsigned flags);
|
unsigned flags);
|
||||||
|
|
||||||
bool
|
|
||||||
sc_adb_uninstall(struct sc_intr *intr, const char *serial, const char *pkg,
|
|
||||||
unsigned flags);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute `adb tcpip <port>`
|
* Execute `adb tcpip <port>`
|
||||||
*/
|
*/
|
||||||
@@ -120,18 +114,4 @@ sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
|
|||||||
char *
|
char *
|
||||||
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);
|
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the path of the installed APK for com.genymobile.scrcpy (if any)
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
sc_adb_get_installed_apk_path(struct sc_intr *intr, const char *serial,
|
|
||||||
unsigned flags);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the version of the installed APK for com.genymobile.scrcpy (if any)
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
sc_adb_get_installed_apk_version(struct sc_intr *intr, const char *serial,
|
|
||||||
unsigned flags);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ sc_adb_parse_device_ip_from_line(char *line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
sc_adb_parse_device_ip(char *str) {
|
sc_adb_parse_device_ip_from_output(char *str) {
|
||||||
size_t idx_line = 0;
|
size_t idx_line = 0;
|
||||||
while (str[idx_line] != '\0') {
|
while (str[idx_line] != '\0') {
|
||||||
char *line = &str[idx_line];
|
char *line = &str[idx_line];
|
||||||
@@ -225,62 +225,3 @@ sc_adb_parse_device_ip(char *str) {
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
|
||||||
sc_adb_parse_installed_apk_path(char *str) {
|
|
||||||
// str is expected to look like:
|
|
||||||
// "package:/data/app/.../base.apk=com.genymobile.scrcpy"
|
|
||||||
// ^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
// We want to extract the path (which may contain '=', even in practice)
|
|
||||||
|
|
||||||
if (strncmp(str, "package:", 8)) {
|
|
||||||
// Does not start with "package:"
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *s = str + 8;
|
|
||||||
size_t len = strcspn(s, " \r\n");
|
|
||||||
s[len] = '\0';
|
|
||||||
|
|
||||||
char *p = strrchr(s, '=');
|
|
||||||
if (!p) {
|
|
||||||
// No '=' found
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truncate at the last '='
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
return strdup(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
sc_adb_parse_installed_apk_version(const char *str) {
|
|
||||||
// str is the (beginning of the) output of `dumpsys package`
|
|
||||||
// We want to extract the version string from a line starting with 4 spaces
|
|
||||||
// then `versionName=` then the version string.
|
|
||||||
|
|
||||||
#define VERSION_NAME_PREFIX "\n versionName="
|
|
||||||
char *s = strstr(str, VERSION_NAME_PREFIX);
|
|
||||||
if (!s) {
|
|
||||||
// Not found
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
s+= sizeof(VERSION_NAME_PREFIX) - 1;
|
|
||||||
|
|
||||||
size_t len = strspn(s, "0123456789.");
|
|
||||||
if (!len) {
|
|
||||||
LOGW("Unexpected version name with no value");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *version = malloc(len + 1);
|
|
||||||
if (!version) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(version, s, len);
|
|
||||||
version[len] = '\0';
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -25,26 +25,6 @@ sc_adb_parse_devices(char *str, struct sc_vec_adb_devices *out_vec);
|
|||||||
* Warning: this function modifies the buffer for optimization purposes.
|
* Warning: this function modifies the buffer for optimization purposes.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
sc_adb_parse_device_ip(char *str);
|
sc_adb_parse_device_ip_from_output(char *str);
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the package path from the output of
|
|
||||||
* `adb shell pm list packages -f <package>`
|
|
||||||
*
|
|
||||||
* The parameter must be a NUL-terminated string.
|
|
||||||
*
|
|
||||||
* Warning: this function modifies the buffer for optimization purposes.
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
sc_adb_parse_installed_apk_path(char *str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the package version from the output of
|
|
||||||
* `adb shell dumpsys package <package>`
|
|
||||||
*
|
|
||||||
* The parameter must be a NUL-terminated string.
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
sc_adb_parse_installed_apk_version(const char *str);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -57,8 +57,6 @@
|
|||||||
#define OPT_NO_CLEANUP 1037
|
#define OPT_NO_CLEANUP 1037
|
||||||
#define OPT_PRINT_FPS 1038
|
#define OPT_PRINT_FPS 1038
|
||||||
#define OPT_NO_POWER_ON 1039
|
#define OPT_NO_POWER_ON 1039
|
||||||
#define OPT_INSTALL 1040
|
|
||||||
#define OPT_REINSTALL 1041
|
|
||||||
|
|
||||||
struct sc_option {
|
struct sc_option {
|
||||||
char shortopt;
|
char shortopt;
|
||||||
@@ -209,12 +207,6 @@ static const struct sc_option options[] = {
|
|||||||
.longopt = "help",
|
.longopt = "help",
|
||||||
.text = "Print this help.",
|
.text = "Print this help.",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.longopt_id = OPT_INSTALL,
|
|
||||||
.longopt = "install",
|
|
||||||
.text = "Install the server (via 'adb install') instead of just "
|
|
||||||
"pushing it (via 'adb push').",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_LEGACY_PASTE,
|
.longopt_id = OPT_LEGACY_PASTE,
|
||||||
.longopt = "legacy-paste",
|
.longopt = "legacy-paste",
|
||||||
@@ -386,13 +378,6 @@ static const struct sc_option options[] = {
|
|||||||
.argdesc = "format",
|
.argdesc = "format",
|
||||||
.text = "Force recording format (either mp4 or mkv).",
|
.text = "Force recording format (either mp4 or mkv).",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.longopt_id = OPT_REINSTALL,
|
|
||||||
.longopt = "reinstall",
|
|
||||||
.text = "Reinstall the server (via 'adb install'), even if the correct "
|
|
||||||
"version is already installed.\n"
|
|
||||||
"Implies --install.",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_RENDER_DRIVER,
|
.longopt_id = OPT_RENDER_DRIVER,
|
||||||
.longopt = "render-driver",
|
.longopt = "render-driver",
|
||||||
@@ -1625,13 +1610,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
case OPT_PRINT_FPS:
|
case OPT_PRINT_FPS:
|
||||||
opts->start_fps_counter = true;
|
opts->start_fps_counter = true;
|
||||||
break;
|
break;
|
||||||
case OPT_INSTALL:
|
|
||||||
opts->install = true;
|
|
||||||
break;
|
|
||||||
case OPT_REINSTALL:
|
|
||||||
opts->install = true;
|
|
||||||
opts->reinstall = true;
|
|
||||||
break;
|
|
||||||
case OPT_OTG:
|
case OPT_OTG:
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_USB
|
||||||
opts->otg = true;
|
opts->otg = true;
|
||||||
|
|||||||
@@ -65,6 +65,4 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||||||
.cleanup = true,
|
.cleanup = true,
|
||||||
.start_fps_counter = false,
|
.start_fps_counter = false,
|
||||||
.power_on = true,
|
.power_on = true,
|
||||||
.install = false,
|
|
||||||
.reinstall = false,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -140,8 +140,6 @@ struct scrcpy_options {
|
|||||||
bool cleanup;
|
bool cleanup;
|
||||||
bool start_fps_counter;
|
bool start_fps_counter;
|
||||||
bool power_on;
|
bool power_on;
|
||||||
bool install;
|
|
||||||
bool reinstall;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct scrcpy_options scrcpy_options_default;
|
extern const struct scrcpy_options scrcpy_options_default;
|
||||||
|
|||||||
@@ -325,8 +325,6 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
.tcpip_dst = options->tcpip_dst,
|
.tcpip_dst = options->tcpip_dst,
|
||||||
.cleanup = options->cleanup,
|
.cleanup = options->cleanup,
|
||||||
.power_on = options->power_on,
|
.power_on = options->power_on,
|
||||||
.install = options->install,
|
|
||||||
.reinstall = options->reinstall,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sc_server_callbacks cbs = {
|
static const struct sc_server_callbacks cbs = {
|
||||||
|
|||||||
@@ -14,11 +14,10 @@
|
|||||||
#include "util/process_intr.h"
|
#include "util/process_intr.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
|
|
||||||
#define SC_SERVER_FILENAME "scrcpy-server.apk"
|
#define SC_SERVER_FILENAME "scrcpy-server"
|
||||||
#define SC_SERVER_PACKAGE "com.genymobile.scrcpy"
|
|
||||||
|
|
||||||
#define SC_SERVER_PATH_DEFAULT PREFIX "/share/scrcpy/" SC_SERVER_FILENAME
|
#define SC_SERVER_PATH_DEFAULT PREFIX "/share/scrcpy/" SC_SERVER_FILENAME
|
||||||
#define SC_DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.apk"
|
#define SC_DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_server_path(void) {
|
get_server_path(void) {
|
||||||
@@ -105,10 +104,7 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
push_server(struct sc_intr *intr, const char *serial, bool install,
|
push_server(struct sc_intr *intr, const char *serial) {
|
||||||
bool reinstall) {
|
|
||||||
assert(install || !reinstall); // reinstall implies install
|
|
||||||
|
|
||||||
char *server_path = get_server_path();
|
char *server_path = get_server_path();
|
||||||
if (!server_path) {
|
if (!server_path) {
|
||||||
return false;
|
return false;
|
||||||
@@ -118,28 +114,7 @@ push_server(struct sc_intr *intr, const char *serial, bool install,
|
|||||||
free(server_path);
|
free(server_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool ok;
|
bool ok = sc_adb_push(intr, serial, server_path, SC_DEVICE_SERVER_PATH, 0);
|
||||||
|
|
||||||
if (install) {
|
|
||||||
char *version = sc_adb_get_installed_apk_version(intr, serial, 0);
|
|
||||||
bool same_version = version && !strcmp(version, SCRCPY_VERSION);
|
|
||||||
free(version);
|
|
||||||
if (!reinstall && same_version) {
|
|
||||||
LOGI("Server " SCRCPY_VERSION " already installed");
|
|
||||||
ok = true;
|
|
||||||
} else {
|
|
||||||
LOGI("Installing server " SCRCPY_VERSION);
|
|
||||||
// If a server with a different signature is installed, or if a
|
|
||||||
// newer server is already installed, we must uninstall it first.
|
|
||||||
ok = sc_adb_uninstall(intr, serial, SC_SERVER_PACKAGE,
|
|
||||||
SC_ADB_SILENT);
|
|
||||||
(void) ok; // expected to fail if it is not installed
|
|
||||||
ok = sc_adb_install(intr, serial, server_path, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ok = sc_adb_push(intr, serial, server_path, SC_DEVICE_SERVER_PATH, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(server_path);
|
free(server_path);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@@ -177,38 +152,6 @@ sc_server_sleep(struct sc_server *server, sc_tick deadline) {
|
|||||||
return !stopped;
|
return !stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
|
||||||
get_classpath_cmd(struct sc_intr *intr, const char *serial, bool install) {
|
|
||||||
if (!install) {
|
|
||||||
// In push mode, the path is known statically
|
|
||||||
char *cp = strdup("CLASSPATH=" SC_DEVICE_SERVER_PATH);
|
|
||||||
if (!cp) {
|
|
||||||
LOG_OOM();
|
|
||||||
}
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *apk_path = sc_adb_get_installed_apk_path(intr, serial, 0);
|
|
||||||
if (!apk_path) {
|
|
||||||
LOGE("Could not get device apk path");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PREFIX_SIZE (sizeof("CLASSPATH=") - 1)
|
|
||||||
size_t len = strlen(apk_path);
|
|
||||||
char *cp = malloc(PREFIX_SIZE + len + 1);
|
|
||||||
if (!cp) {
|
|
||||||
LOG_OOM();
|
|
||||||
free(apk_path);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(cp, "CLASSPATH=", PREFIX_SIZE);
|
|
||||||
memcpy(cp + PREFIX_SIZE, apk_path, len + 1);
|
|
||||||
free(apk_path);
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sc_pid
|
static sc_pid
|
||||||
execute_server(struct sc_server *server,
|
execute_server(struct sc_server *server,
|
||||||
const struct sc_server_params *params) {
|
const struct sc_server_params *params) {
|
||||||
@@ -217,20 +160,13 @@ execute_server(struct sc_server *server,
|
|||||||
const char *serial = server->serial;
|
const char *serial = server->serial;
|
||||||
assert(serial);
|
assert(serial);
|
||||||
|
|
||||||
char *classpath = get_classpath_cmd(&server->intr, serial, params->install);
|
|
||||||
if (!classpath) {
|
|
||||||
return SC_PROCESS_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGD("Using %s", classpath);
|
|
||||||
|
|
||||||
const char *cmd[128];
|
const char *cmd[128];
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
cmd[count++] = sc_adb_get_executable();
|
cmd[count++] = sc_adb_get_executable();
|
||||||
cmd[count++] = "-s";
|
cmd[count++] = "-s";
|
||||||
cmd[count++] = serial;
|
cmd[count++] = serial;
|
||||||
cmd[count++] = "shell";
|
cmd[count++] = "shell";
|
||||||
cmd[count++] = classpath;
|
cmd[count++] = "CLASSPATH=" SC_DEVICE_SERVER_PATH;
|
||||||
cmd[count++] = "app_process";
|
cmd[count++] = "app_process";
|
||||||
|
|
||||||
#ifdef SERVER_DEBUGGER
|
#ifdef SERVER_DEBUGGER
|
||||||
@@ -316,8 +252,6 @@ execute_server(struct sc_server *server,
|
|||||||
// By default, power_on is true
|
// By default, power_on is true
|
||||||
ADD_PARAM("power_on=false");
|
ADD_PARAM("power_on=false");
|
||||||
}
|
}
|
||||||
// TODO ADD_PARAM("install=…");
|
|
||||||
// The server must not rm in /data/local/tmp if installed
|
|
||||||
|
|
||||||
#undef ADD_PARAM
|
#undef ADD_PARAM
|
||||||
|
|
||||||
@@ -338,8 +272,6 @@ execute_server(struct sc_server *server,
|
|||||||
pid = sc_adb_execute(cmd, 0);
|
pid = sc_adb_execute(cmd, 0);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
free(classpath);
|
|
||||||
|
|
||||||
for (unsigned i = dyn_idx; i < count; ++i) {
|
for (unsigned i = dyn_idx; i < count; ++i) {
|
||||||
free((char *) cmd[i]);
|
free((char *) cmd[i]);
|
||||||
}
|
}
|
||||||
@@ -823,9 +755,8 @@ run_server(void *data) {
|
|||||||
assert(serial);
|
assert(serial);
|
||||||
LOGD("Device serial: %s", serial);
|
LOGD("Device serial: %s", serial);
|
||||||
|
|
||||||
ok = push_server(&server->intr, serial, params->install, params->reinstall);
|
ok = push_server(&server->intr, serial);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Failed to push server");
|
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ struct sc_server_params {
|
|||||||
bool select_tcpip;
|
bool select_tcpip;
|
||||||
bool cleanup;
|
bool cleanup;
|
||||||
bool power_on;
|
bool power_on;
|
||||||
bool install;
|
|
||||||
bool reinstall;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_server {
|
struct sc_server {
|
||||||
|
|||||||
51
app/src/stream.h
Normal file
51
app/src/stream.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef STREAM_H
|
||||||
|
#define STREAM_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
#include "trait/packet_sink.h"
|
||||||
|
#include "util/net.h"
|
||||||
|
#include "util/thread.h"
|
||||||
|
|
||||||
|
#define STREAM_MAX_SINKS 2
|
||||||
|
|
||||||
|
struct stream {
|
||||||
|
sc_socket socket;
|
||||||
|
sc_thread thread;
|
||||||
|
|
||||||
|
struct sc_packet_sink *sinks[STREAM_MAX_SINKS];
|
||||||
|
unsigned sink_count;
|
||||||
|
|
||||||
|
AVCodecContext *codec_ctx;
|
||||||
|
AVCodecParserContext *parser;
|
||||||
|
// successive packets may need to be concatenated, until a non-config
|
||||||
|
// packet is available
|
||||||
|
AVPacket *pending;
|
||||||
|
|
||||||
|
const struct stream_callbacks *cbs;
|
||||||
|
void *cbs_userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stream_callbacks {
|
||||||
|
void (*on_eos)(struct stream *stream, void *userdata);
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
stream_init(struct stream *stream, sc_socket socket,
|
||||||
|
const struct stream_callbacks *cbs, void *cbs_userdata);
|
||||||
|
|
||||||
|
void
|
||||||
|
stream_add_sink(struct stream *stream, struct sc_packet_sink *sink);
|
||||||
|
|
||||||
|
bool
|
||||||
|
stream_start(struct stream *stream);
|
||||||
|
|
||||||
|
void
|
||||||
|
stream_join(struct stream *stream);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "adb/adb_device.h"
|
#include "adb/adb_device.h"
|
||||||
#include "adb/adb_parser.h"
|
#include "adb/adb_parser.h"
|
||||||
|
|
||||||
static void test_adb_devices(void) {
|
static void test_adb_devices() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"List of devices attached\n"
|
"List of devices attached\n"
|
||||||
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
||||||
@@ -31,7 +31,7 @@ static void test_adb_devices(void) {
|
|||||||
sc_adb_devices_destroy(&vec);
|
sc_adb_devices_destroy(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_cr(void) {
|
static void test_adb_devices_cr() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"List of devices attached\r\n"
|
"List of devices attached\r\n"
|
||||||
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
||||||
@@ -57,7 +57,7 @@ static void test_adb_devices_cr(void) {
|
|||||||
sc_adb_devices_destroy(&vec);
|
sc_adb_devices_destroy(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_daemon_start(void) {
|
static void test_adb_devices_daemon_start() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"* daemon not running; starting now at tcp:5037\n"
|
"* daemon not running; starting now at tcp:5037\n"
|
||||||
"* daemon started successfully\n"
|
"* daemon started successfully\n"
|
||||||
@@ -78,7 +78,7 @@ static void test_adb_devices_daemon_start(void) {
|
|||||||
sc_adb_devices_destroy(&vec);
|
sc_adb_devices_destroy(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_daemon_start_mixed(void) {
|
static void test_adb_devices_daemon_start_mixed() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"List of devices attached\n"
|
"List of devices attached\n"
|
||||||
"adb server version (41) doesn't match this client (39); killing...\n"
|
"adb server version (41) doesn't match this client (39); killing...\n"
|
||||||
@@ -105,7 +105,7 @@ static void test_adb_devices_daemon_start_mixed(void) {
|
|||||||
sc_adb_devices_destroy(&vec);
|
sc_adb_devices_destroy(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_without_eol(void) {
|
static void test_adb_devices_without_eol() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"List of devices attached\n"
|
"List of devices attached\n"
|
||||||
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
||||||
@@ -124,7 +124,7 @@ static void test_adb_devices_without_eol(void) {
|
|||||||
sc_adb_devices_destroy(&vec);
|
sc_adb_devices_destroy(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_without_header(void) {
|
static void test_adb_devices_without_header() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
"0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "
|
||||||
"device:MyDevice transport_id:1\n";
|
"device:MyDevice transport_id:1\n";
|
||||||
@@ -134,7 +134,7 @@ static void test_adb_devices_without_header(void) {
|
|||||||
assert(!ok);
|
assert(!ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_corrupted(void) {
|
static void test_adb_devices_corrupted() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"List of devices attached\n"
|
"List of devices attached\n"
|
||||||
"corrupted_garbage\n";
|
"corrupted_garbage\n";
|
||||||
@@ -145,7 +145,7 @@ static void test_adb_devices_corrupted(void) {
|
|||||||
assert(vec.size == 0);
|
assert(vec.size == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_adb_devices_spaces(void) {
|
static void test_adb_devices_spaces() {
|
||||||
char output[] =
|
char output[] =
|
||||||
"List of devices attached\n"
|
"List of devices attached\n"
|
||||||
"0123456789abcdef unauthorized usb:1-4 transport_id:3\n";
|
"0123456789abcdef unauthorized usb:1-4 transport_id:3\n";
|
||||||
@@ -163,132 +163,84 @@ static void test_adb_devices_spaces(void) {
|
|||||||
sc_adb_devices_destroy(&vec);
|
sc_adb_devices_destroy(&vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_single_line(void) {
|
static void test_get_ip_single_line() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
||||||
"192.168.12.34\r\r\n";
|
"192.168.12.34\r\r\n";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
assert(!strcmp(ip, "192.168.12.34"));
|
assert(!strcmp(ip, "192.168.12.34"));
|
||||||
free(ip);
|
free(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_single_line_without_eol(void) {
|
static void test_get_ip_single_line_without_eol() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
||||||
"192.168.12.34";
|
"192.168.12.34";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
assert(!strcmp(ip, "192.168.12.34"));
|
assert(!strcmp(ip, "192.168.12.34"));
|
||||||
free(ip);
|
free(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_single_line_with_trailing_space(void) {
|
static void test_get_ip_single_line_with_trailing_space() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
||||||
"192.168.12.34 \n";
|
"192.168.12.34 \n";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
assert(!strcmp(ip, "192.168.12.34"));
|
assert(!strcmp(ip, "192.168.12.34"));
|
||||||
free(ip);
|
free(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_multiline_first_ok(void) {
|
static void test_get_ip_multiline_first_ok() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
||||||
"192.168.1.2\r\n"
|
"192.168.1.2\r\n"
|
||||||
"10.0.0.0/24 dev rmnet proto kernel scope link src "
|
"10.0.0.0/24 dev rmnet proto kernel scope link src "
|
||||||
"10.0.0.2\r\n";
|
"10.0.0.2\r\n";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
assert(!strcmp(ip, "192.168.1.2"));
|
assert(!strcmp(ip, "192.168.1.2"));
|
||||||
free(ip);
|
free(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_multiline_second_ok(void) {
|
static void test_get_ip_multiline_second_ok() {
|
||||||
char ip_route[] = "10.0.0.0/24 dev rmnet proto kernel scope link src "
|
char ip_route[] = "10.0.0.0/24 dev rmnet proto kernel scope link src "
|
||||||
"10.0.0.3\r\n"
|
"10.0.0.3\r\n"
|
||||||
"192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
"192.168.1.0/24 dev wlan0 proto kernel scope link src "
|
||||||
"192.168.1.3\r\n";
|
"192.168.1.3\r\n";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
assert(!strcmp(ip, "192.168.1.3"));
|
assert(!strcmp(ip, "192.168.1.3"));
|
||||||
free(ip);
|
free(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_no_wlan(void) {
|
static void test_get_ip_no_wlan() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
|
||||||
"192.168.12.34\r\r\n";
|
"192.168.12.34\r\r\n";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(!ip);
|
assert(!ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_no_wlan_without_eol(void) {
|
static void test_get_ip_no_wlan_without_eol() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
|
||||||
"192.168.12.34";
|
"192.168.12.34";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(!ip);
|
assert(!ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_get_ip_truncated(void) {
|
static void test_get_ip_truncated() {
|
||||||
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
|
char ip_route[] = "192.168.1.0/24 dev rmnet proto kernel scope link src "
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
char *ip = sc_adb_parse_device_ip(ip_route);
|
char *ip = sc_adb_parse_device_ip_from_output(ip_route);
|
||||||
assert(!ip);
|
assert(!ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_apk_path(void) {
|
|
||||||
char str[] = "package:/data/app/~~71mguyc6p-kNjQdNaNkToA==/com.genymobile."
|
|
||||||
"scrcpy-l6fiqqUSU7Ok7QLg-rIyJA==/base.apk=com.genymobile."
|
|
||||||
"scrcpy\n";
|
|
||||||
|
|
||||||
const char *expected = "/data/app/~~71mguyc6p-kNjQdNaNkToA==/com.genymobile"
|
|
||||||
".scrcpy-l6fiqqUSU7Ok7QLg-rIyJA==/base.apk";
|
|
||||||
char *path = sc_adb_parse_installed_apk_path(str);
|
|
||||||
assert(!strcmp(path, expected));
|
|
||||||
free(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_apk_path_invalid(void) {
|
|
||||||
// Does not start with "package:"
|
|
||||||
char str[] = "garbage:/data/app/~~71mguyc6p-kNjQdNaNkToA==/com.genymobile."
|
|
||||||
"scrcpy-l6fiqqUSU7Ok7QLg-rIyJA==/base.apk=com.genymobile."
|
|
||||||
"scrcpy\n";
|
|
||||||
|
|
||||||
char *path = sc_adb_parse_installed_apk_path(str);
|
|
||||||
assert(!path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_apk_version(void) {
|
|
||||||
char str[] =
|
|
||||||
"Key Set Manager:\n"
|
|
||||||
" [com.genymobile.scrcpy]\n"
|
|
||||||
" Signing KeySets: 128\n"
|
|
||||||
"\n"
|
|
||||||
"Packages:\n"
|
|
||||||
" Package [com.genymobile.scrcpy] (89abcdef):\n"
|
|
||||||
" userId=12345\n"
|
|
||||||
" pkg=Package{012345 com.genymobile.scrcpy}\n"
|
|
||||||
" codePath=/data/app/~~abcdef==/com.genymobile.scrcpy-012345==\n"
|
|
||||||
" resourcePath=/data/app/~~abcdef==/com.genymobile.scrcpy-013245==\n"
|
|
||||||
" primaryCpuAbi=null\n"
|
|
||||||
" secondaryCpuAbi=null\n"
|
|
||||||
" versionCode=12400 minSdk=21 targetSdk=31\n"
|
|
||||||
" versionName=1.24\n"
|
|
||||||
" splits=[base]\n"
|
|
||||||
" apkSigningVersion=2\n"
|
|
||||||
" applicationInfo=ApplicationInfo{012345 com.genymobile.scrcpy}\n";
|
|
||||||
|
|
||||||
const char *expected = "1.24";
|
|
||||||
char *version = sc_adb_parse_installed_apk_version(str);
|
|
||||||
assert(!strcmp(version, expected));
|
|
||||||
free(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
@@ -310,10 +262,4 @@ int main(int argc, char *argv[]) {
|
|||||||
test_get_ip_no_wlan();
|
test_get_ip_no_wlan();
|
||||||
test_get_ip_no_wlan_without_eol();
|
test_get_ip_no_wlan_without_eol();
|
||||||
test_get_ip_truncated();
|
test_get_ip_truncated();
|
||||||
|
|
||||||
test_apk_path();
|
|
||||||
test_apk_path_invalid();
|
|
||||||
test_apk_version();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
2
run
2
run
@@ -21,5 +21,5 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
SCRCPY_ICON_PATH="app/data/icon.png" \
|
SCRCPY_ICON_PATH="app/data/icon.png" \
|
||||||
SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server.apk" \
|
SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server" \
|
||||||
"$BUILDDIR/app/scrcpy" "$@"
|
"$BUILDDIR/app/scrcpy" "$@"
|
||||||
|
|||||||
1
server/.gitignore
vendored
1
server/.gitignore
vendored
@@ -6,4 +6,3 @@
|
|||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
/keystore.properties
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
For an APK to be installable, it must be signed: <https://developer.android.com/training/articles/keystore>
|
|
||||||
|
|
||||||
For that purpose, create a keystore by executing this command:
|
|
||||||
|
|
||||||
keytool -genkey -v -keystore ~/.android/scrcpy.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias scrcpy -dname cn=scrcpy
|
|
||||||
|
|
||||||
(Adapt ~/.android/scrcpy.keystore if you want to generate it to another location.)
|
|
||||||
|
|
||||||
Then create server/keystore.properties and edit its properties:
|
|
||||||
|
|
||||||
cp keystore.properties.sample keystore.properties
|
|
||||||
vim keystore.properties # fill the properties
|
|
||||||
@@ -10,31 +10,16 @@ android {
|
|||||||
versionName "1.24"
|
versionName "1.24"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
signingConfigs {
|
|
||||||
release {
|
|
||||||
// to be defined in server/keystore.properties (see server/HOWTO_keystore.txt)
|
|
||||||
def keystorePropsFile = rootProject.file("server/keystore.properties")
|
|
||||||
if (keystorePropsFile.exists()) {
|
|
||||||
def props = new Properties()
|
|
||||||
props.load(new FileInputStream(keystorePropsFile))
|
|
||||||
|
|
||||||
storeFile rootProject.file(props['storeFile'])
|
|
||||||
storePassword props['storePassword']
|
|
||||||
keyAlias props['keyAlias']
|
|
||||||
keyPassword props['keyPassword']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
testImplementation 'junit:junit:4.13.1'
|
testImplementation 'junit:junit:4.13.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,42 +14,13 @@ set -e
|
|||||||
SCRCPY_DEBUG=false
|
SCRCPY_DEBUG=false
|
||||||
SCRCPY_VERSION_NAME=1.24
|
SCRCPY_VERSION_NAME=1.24
|
||||||
|
|
||||||
SERVER_DIR="$(realpath $(dirname "$0"))"
|
|
||||||
KEYSTORE_PROPERTIES_FILE="$SERVER_DIR/keystore.properties"
|
|
||||||
|
|
||||||
if [[ ! -f "$KEYSTORE_PROPERTIES_FILE" ]]
|
|
||||||
then
|
|
||||||
echo "The file '$KEYSTORE_PROPERTIES_FILE' does not exist." >&2
|
|
||||||
echo "Please read '$SERVER_DIR/HOWTO_keystore.txt'." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
declare -A props
|
|
||||||
while IFS='=' read -r key value
|
|
||||||
do
|
|
||||||
props["$key"]="$value"
|
|
||||||
done < "$KEYSTORE_PROPERTIES_FILE"
|
|
||||||
|
|
||||||
KEYSTORE_FILE=${props['storeFile']}
|
|
||||||
KEYSTORE_PASSWORD=${props['storePassword']}
|
|
||||||
KEYSTORE_KEY_ALIAS=${props['keyAlias']}
|
|
||||||
KEYSTORE_KEY_PASSWORD=${props['keyPassword']}
|
|
||||||
|
|
||||||
if [[ ! -f "$KEYSTORE_FILE" ]]
|
|
||||||
then
|
|
||||||
echo "Keystore '$KEYSTORE_FILE' (read from '$KEYSTORE_PROPERTIES_FILE')" \
|
|
||||||
"does not exist." >&2
|
|
||||||
echo "Please read '$SERVER_DIR/HOWTO_keystore.txt'." >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
PLATFORM=${ANDROID_PLATFORM:-31}
|
PLATFORM=${ANDROID_PLATFORM:-31}
|
||||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-31.0.0}
|
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-31.0.0}
|
||||||
BUILD_TOOLS_DIR="$ANDROID_HOME/build-tools/$BUILD_TOOLS"
|
|
||||||
|
|
||||||
BUILD_DIR="$(realpath ${BUILD_DIR:-build_manual})"
|
BUILD_DIR="$(realpath ${BUILD_DIR:-build_manual})"
|
||||||
CLASSES_DIR="$BUILD_DIR/classes"
|
CLASSES_DIR="$BUILD_DIR/classes"
|
||||||
SERVER_BINARY=scrcpy-server.apk
|
SERVER_DIR=$(dirname "$0")
|
||||||
|
SERVER_BINARY=scrcpy-server
|
||||||
ANDROID_JAR="$ANDROID_HOME/platforms/android-$PLATFORM/android.jar"
|
ANDROID_JAR="$ANDROID_HOME/platforms/android-$PLATFORM/android.jar"
|
||||||
|
|
||||||
echo "Platform: android-$PLATFORM"
|
echo "Platform: android-$PLATFORM"
|
||||||
@@ -70,8 +41,9 @@ EOF
|
|||||||
|
|
||||||
echo "Generating java from aidl..."
|
echo "Generating java from aidl..."
|
||||||
cd "$SERVER_DIR/src/main/aidl"
|
cd "$SERVER_DIR/src/main/aidl"
|
||||||
"$BUILD_TOOLS_DIR/aidl" -o"$CLASSES_DIR" android/view/IRotationWatcher.aidl
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/aidl" -o"$CLASSES_DIR" \
|
||||||
"$BUILD_TOOLS_DIR/aidl" -o"$CLASSES_DIR" \
|
android/view/IRotationWatcher.aidl
|
||||||
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/aidl" -o"$CLASSES_DIR" \
|
||||||
android/content/IOnPrimaryClipChangedListener.aidl
|
android/content/IOnPrimaryClipChangedListener.aidl
|
||||||
|
|
||||||
echo "Compiling java sources..."
|
echo "Compiling java sources..."
|
||||||
@@ -87,15 +59,20 @@ cd "$CLASSES_DIR"
|
|||||||
if [[ $PLATFORM -lt 31 ]]
|
if [[ $PLATFORM -lt 31 ]]
|
||||||
then
|
then
|
||||||
# use dx
|
# use dx
|
||||||
"$BUILD_TOOLS_DIR/dx" --dex --output "$BUILD_DIR/classes.dex" \
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/dx" --dex \
|
||||||
|
--output "$BUILD_DIR/classes.dex" \
|
||||||
android/view/*.class \
|
android/view/*.class \
|
||||||
android/content/*.class \
|
android/content/*.class \
|
||||||
com/genymobile/scrcpy/*.class \
|
com/genymobile/scrcpy/*.class \
|
||||||
com/genymobile/scrcpy/wrappers/*.class
|
com/genymobile/scrcpy/wrappers/*.class
|
||||||
|
|
||||||
|
echo "Archiving..."
|
||||||
cd "$BUILD_DIR"
|
cd "$BUILD_DIR"
|
||||||
|
jar cvf "$SERVER_BINARY" classes.dex
|
||||||
|
rm -rf classes.dex classes
|
||||||
else
|
else
|
||||||
# use d8
|
# use d8
|
||||||
"$BUILD_TOOLS_DIR/d8" --classpath "$ANDROID_JAR" \
|
"$ANDROID_HOME/build-tools/$BUILD_TOOLS/d8" --classpath "$ANDROID_JAR" \
|
||||||
--output "$BUILD_DIR/classes.zip" \
|
--output "$BUILD_DIR/classes.zip" \
|
||||||
android/view/*.class \
|
android/view/*.class \
|
||||||
android/content/*.class \
|
android/content/*.class \
|
||||||
@@ -103,24 +80,8 @@ else
|
|||||||
com/genymobile/scrcpy/wrappers/*.class
|
com/genymobile/scrcpy/wrappers/*.class
|
||||||
|
|
||||||
cd "$BUILD_DIR"
|
cd "$BUILD_DIR"
|
||||||
unzip -o classes.zip classes.dex # we need the inner classes.dex
|
mv classes.zip "$SERVER_BINARY"
|
||||||
|
rm -rf classes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Packaging..."
|
|
||||||
# note: if a res directory exists, add: -S "$SERVER_DIR/src/main/res"
|
|
||||||
"$BUILD_TOOLS_DIR/aapt" package -f \
|
|
||||||
-M "$SERVER_DIR/src/main/AndroidManifest.xml" \
|
|
||||||
-I "$ANDROID_JAR" \
|
|
||||||
-F "$SERVER_BINARY.unaligned"
|
|
||||||
"$BUILD_TOOLS_DIR/aapt" add "$SERVER_BINARY.unaligned" classes.dex
|
|
||||||
"$BUILD_TOOLS_DIR/zipalign" -p 4 "$SERVER_BINARY.unaligned" "$SERVER_BINARY"
|
|
||||||
rm "$SERVER_BINARY.unaligned"
|
|
||||||
|
|
||||||
"$BUILD_TOOLS_DIR/apksigner" sign \
|
|
||||||
--ks "$KEYSTORE_FILE" \
|
|
||||||
--ks-pass "pass:$KEYSTORE_PASSWORD" \
|
|
||||||
--ks-key-alias "$KEYSTORE_KEY_ALIAS" \
|
|
||||||
--key-pass "pass:$KEYSTORE_KEY_PASSWORD" \
|
|
||||||
"$SERVER_BINARY"
|
|
||||||
|
|
||||||
echo "Server generated in $BUILD_DIR/$SERVER_BINARY"
|
echo "Server generated in $BUILD_DIR/$SERVER_BINARY"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
storeFile=/path/to/your/keystore
|
|
||||||
storePassword=PASSWORD
|
|
||||||
keyAlias=scrcpy
|
|
||||||
keyPassword=PASSWORD
|
|
||||||
@@ -6,7 +6,7 @@ if prebuilt_server == ''
|
|||||||
# gradle is responsible for tracking source changes
|
# gradle is responsible for tracking source changes
|
||||||
build_by_default: true,
|
build_by_default: true,
|
||||||
build_always_stale: true,
|
build_always_stale: true,
|
||||||
output: 'scrcpy-server.apk',
|
output: 'scrcpy-server',
|
||||||
command: [find_program('./scripts/build-wrapper.sh'), meson.current_source_dir(), '@OUTPUT@', get_option('buildtype')],
|
command: [find_program('./scripts/build-wrapper.sh'), meson.current_source_dir(), '@OUTPUT@', get_option('buildtype')],
|
||||||
console: true,
|
console: true,
|
||||||
install: true,
|
install: true,
|
||||||
@@ -18,7 +18,7 @@ else
|
|||||||
endif
|
endif
|
||||||
custom_target('scrcpy-server-prebuilt',
|
custom_target('scrcpy-server-prebuilt',
|
||||||
input: prebuilt_server,
|
input: prebuilt_server,
|
||||||
output: 'scrcpy-server.apk',
|
output: 'scrcpy-server',
|
||||||
command: ['cp', '@INPUT@', '@OUTPUT@'],
|
command: ['cp', '@INPUT@', '@OUTPUT@'],
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: 'share/scrcpy')
|
install_dir: 'share/scrcpy')
|
||||||
|
|||||||
@@ -25,5 +25,5 @@ then
|
|||||||
cp "$PROJECT_ROOT/build/outputs/apk/debug/server-debug.apk" "$OUTPUT"
|
cp "$PROJECT_ROOT/build/outputs/apk/debug/server-debug.apk" "$OUTPUT"
|
||||||
else
|
else
|
||||||
"$GRADLE" -p "$PROJECT_ROOT" assembleRelease
|
"$GRADLE" -p "$PROJECT_ROOT" assembleRelease
|
||||||
cp "$PROJECT_ROOT/build/outputs/apk/release/server-release.apk" "$OUTPUT"
|
cp "$PROJECT_ROOT/build/outputs/apk/release/server-release-unsigned.apk" "$OUTPUT"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public final class CleanUp {
|
public final class CleanUp {
|
||||||
|
|
||||||
public static final String SERVER_PATH = "/data/local/tmp/scrcpy-server.apk";
|
public static final String SERVER_PATH = "/data/local/tmp/scrcpy-server.jar";
|
||||||
|
|
||||||
// A simple struct to be passed from the main process to the cleanup process
|
// A simple struct to be passed from the main process to the cleanup process
|
||||||
public static class Config implements Parcelable {
|
public static class Config implements Parcelable {
|
||||||
|
|||||||
Reference in New Issue
Block a user