The function assumed that the raw output of "adb get-serialno" was a
NUL-terminated string, but it is not the case.
It this output did not end with a space or a new line character, then
sc_str_truncate() would write '\0' over the last character. Even worse,
if the output was empty, then sc_str_truncate() would write
out-of-bounds.
Avoid the error-prone sc_str_truncate() util function.
The function assumed that the raw output of "adb getprop" was a
NUL-terminated string, but it is not the case.
It this output did not end with a space or a new line character, then
sc_str_truncate() would write '\0' over the last character. Even worse,
if the output was empty, then sc_str_truncate() would write
out-of-bounds.
Avoid the error-prone sc_str_truncate() util function.
The parser assumed that its input was a NUL-terminated string, but it
was not the case: it is just the raw output of "adb devices ip route".
In practice, it was harmless, since the output always ended with '\n'
(which was replaced by '\0' on truncation), but it was incorrect
nonetheless.
Always write a '\0' at the end of the buffer, and explicitly parse as a
NUL-terminated string. For that purpose, avoid the error-prone
sc_str_truncate() util function.
Before starting the server, the actual device serial (possibly its
ip:port if it's over TCP/IP) must be known.
A serial might be requested via -s/--serial (stored in the
sc_server_params), but the actual serial may change afterwards:
- if none is provided, then it is retrieved with "adb get-serialno";
- if --tcpip is requested, then the final serial will be the target
ip:port.
The requested serial was overwritten by the actual serial in the
sc_server_params struct, which was a bit hacky.
Instead, store a separate serial field in sc_server (and rename the one
from sc_server_params to "req_serial" to avoid confusion).
Now that providing a serial is mandatory for adb commands where it is
relevant, the whole argv array may be built statically, without
allocations at runtime.
If no serial is passed, then the command would work if there is exactly
one device connected, but will fail with multiple devices.
To avoid such cases, ensure that a serial is always provided.
On Windows, adb is provided in the release archive. Most missing adb
issues come from users setting the ADB environment variable to an
incorrect value (on all platforms).
Suggesting to install platform-tools to solve the problem will just make
things worse (there will be one more adb in yet another location).
The function was initially implemented to truncate lines, but was later
generalized to accept custom delimiters. The whole documentation has not
been updated accordingly.
Refs 9619ade706
Add an option --otg to run scrcpy with only physical keyboard and mouse
simulation (HID over AOA), without mirroring and without requiring adb.
To avoid adding complexity into the scrcpy initialization and screen
implementation, OTG mode is implemented totally separately, with a
separate window.
PR #2974 <https://github.com/Genymobile/scrcpy/pull/2974>
Input events helpers to convert from SDL events to scrcpy events were
implemented in input_manager. To reuse them for OTG mode, move them to
input_events.h.
PR #2974 <https://github.com/Genymobile/scrcpy/pull/2974>
The device disconnection is detected when the video socket closes.
In order to introduce an OTG mode (HID events) without mirroring (and
without server), we must be able to detect USB device disconnection.
This feature will only be used in OTG mode.
PR #2974 <https://github.com/Genymobile/scrcpy/pull/2974>
Acksync is used to delay HID events until some request (in practice,
device clipboard synchronization) is acknowledged by the device.
This mechanism will not be necessary for OTG mode.
PR #2974 <https://github.com/Genymobile/scrcpy/pull/2974>
The device was automatically found by sc_usb_connect(). Instead, expose
a function to find a device from a serial, and let the caller connect to
the device found (if any).
This will allow to list all devices first, then select one device to
connect to.
PR #2974 <https://github.com/Genymobile/scrcpy/pull/2974>
Use it from accept_device() to simplify (at the cost an additional
allocation for each serial, but it is not important).
It will also be useful in other functions in further commits.
PR #2974 <https://github.com/Genymobile/scrcpy/pull/2974>
The server needs to interrupt the sockets on stop, but it must not close
them while other threads may attempt to read from or write to them.
In particular, the video_socket is read by the stream thread, and the
control_socket is written by the controller and read by receiver.
Therefore, close the socket only on sc_server_destroy(), which is called
after all other threads are joined.
Reported by TSAN on close:
WARNING: ThreadSanitizer: data race (pid=3287612)
Write of size 8 at 0x7ba000000080 by thread T1:
#0 close ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1690 (libtsan.so.0+0x359d8)
#1 net_close ../app/src/util/net.c:280 (scrcpy+0x23643)
#2 run_server ../app/src/server.c:772 (scrcpy+0x20047)
#3 <null> <null> (libSDL2-2.0.so.0+0x905a0)
Previous read of size 8 at 0x7ba000000080 by thread T16:
#0 recv ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:6603 (libtsan.so.0+0x4f4a6)
#1 net_recv_all ../app/src/util/net.c:228 (scrcpy+0x234a9)
#2 stream_recv_packet ../app/src/stream.c:33 (scrcpy+0x2045c)
#3 run_stream ../app/src/stream.c:228 (scrcpy+0x21169)
#4 <null> <null> (libSDL2-2.0.so.0+0x905a0)
Refs ddb9396743
If --no-control is requested, then the controller instance is not
initialized. However, its reference was still passed to screen and
input_manager.
Instead, pass NULL if no controller is available.
The optimal initial size was computed from the expected dimensions, sent
immediately by the server before encoding any video frame.
However, the actual frame size may be different, for example when the
device encoder does not support the requested size.
To always handle this case properly, position and size the window only
once the first frame size is known.
PR #2947 <https://github.com/Genymobile/scrcpy/pull/2947>
Show the window only after the actual frame size is known (and if no
error has occurred).
This will allow to properly position and size the window when the size
of the first frame is different from the size initially announced by the
server.
PR #2947 <https://github.com/Genymobile/scrcpy/pull/2947>
The components should be configurable independently of the global
scrcpy_options instance: their configuration could be provided
separately, like it is the case for example for some screen parameters.
For consistency, keyboard injection should not depend on scrcpy_options.
In relative mouse mode, the mouse pointer must be "captured" from the
computer.
Toggle (disable/enable) relative mouse mode using any of the hardcoded
capture keys:
- left-Alt
- left-Super
- right-Super
These capture keys do not conflict with shortcuts, since a shortcut is
always a combination of the MOD key and some other key, while the
capture key triggers an action only if it is pressed and released alone.
The relative mouse mode is also automatically enabled on any click in
the window, and automatically disabled on focus lost (it is possible to
lose focus even without the mouse).
The decision to not send motion events when no click is pressed is
specific to Android mouse injection. Other mouse processors (e.g. for
HID mouse) will need to receive all events.
The default mouse injection works in absolute mode: it forwards clicks
at a specific position on screen.
To support HID mouse, add a flag to indicate that the mouse processor
works in relative mode: it forwards mouse motion vectors, without any
absolute reference to the screen.
A scroll event might be produced when a mouse button is pressed (for
example when scrolling while selecting a text). For consistency, pass
the actual buttons state (instead of 0).
In practice, it seems that this use case does not work properly with
Android event injection, but it will work with HID mouse.
The input_manager is strongly tied to the screen, it could not work
independently of the specific screen implementation.
To implement a user-friendly HID mouse behavior, some SDL events
will need to be handled both by the screen and by the input manager. For
example, a click must typically be handled by the input_manager so that
it is forwarded to the device, but in HID mouse mode, the first click
should be handled by the screen to capture the mouse (enable relative
mouse mode).
Make the input_manager a descendant of the screen, so that the screen
decides what to do on SDL events.
Concretely, replace this structure hierarchy:
+- struct scrcpy
+- struct input_manager
+- struct screen
by this one:
+- struct scrcpy
+- struct screen
+- struct input_manager
This avoids to directly pass the options instance (which contains more
data than strictly necessary), and limit the number of parameters for
the init function.
Not all key processors support text injection (HID keyboard does not
support it).
Instead of providing a dummy op function, set it to NULL and check on
the caller side before calling it.
Pass scrcpy input events instead of SDL input events to mouse
processors.
These events represent exactly what mouse processors need, abstracted
from any visual orientation and scaling applied on the SDL window.
This makes the mouse processors independent of the "screen" instance,
and the implementation source code independent of the SDL API.
This aims to make the key/mouse processors independent of the "screen",
by processing scrcpy-specific input events instead of SDL events.
In particular, these scrcpy events are not impacted by any UI window
scaling or rotation (contrary to SDL events).
The input manager exposed functions taking an "actions" parameter,
containing a bitmask-OR of ACTION_UP and ACTION_DOWN.
But they are never called with both actions simultaneously anymore, so
simplify.
Refs 964b6d2243
Refs d0739911a3
This allows to report a meaningful error message if an unsupported
feature is used on an incompatible platform. This is consistent with the
behavior of -K/--hid-keyboard.
The "resize to fit" feature (MOD+w or double-click on black borders)
computed the "optimal size" using the same function computing the
initial window size on start.
However, on "resize to fit", only the black borders must be removed (the
content size must be preserved), so the display bounds must not be
considered.
Since commit 0426708544, the server is run
in a dedicated thread. For SDL, many signals, including SIGINT and
SIGTERM, are masked for new threads. As a result, if the adb server is
not already running, adb commands invoked by scrcpy will start an adb
server that ignores those signals and cannot be terminated at system
shutdown.
Fixes#2873 <https://github.com/Genymobile/scrcpy/issues/2873>
PR #2870 <https://github.com/Genymobile/scrcpy/pull/2870>
Signed-off-by: Romain Vimont <rom@rom1v.com>
Prefix the name of threads by "scrcpy-". This improves readability in
the output of `top -H` for example.
Limit the thread names to 16 bytes, because it is limited on some
platforms.
The sockets were never interrupted or closed by the client since recent
changes to run the server from a dedicated thread (see commit
0426708544).
As a side effect, the server could never terminate properly (it was
waiting on socket blocking calls), so it was always killed by the client
after the WATCHDOG_DELAY.
Interrupt the sockets on stop to give the servera chance to terminate
property, then close them.
If --no-control is enabled, then it is not necessary to create a second
communication socket between the client and the server.
This also facilitates the use of the server alone (without the client)
to receive only the raw video stream.
Thank you clang:
../app/src/control_msg.c:45:5: warning: suspicious concatenation of
string literals in an array initialization; did you mean to separate
the elements with a comma? [-Wstring-concatenation]
"hover-exit",
^
In function ‘memcpy’,
inlined from ‘control_msg_serialize.constprop’ at ../app/src/control_msg.c:77:5,
inlined from ‘run_controller’ at ../app/src/controller.c:69:12:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:10:
warning: ‘__builtin___memcpy_chk’ writing 262138 bytes into a region
of size 262130 overflows the destination [-Wstringop-overflow=]
return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
Refs 901d837165
PR #2859 <https://github.com/Genymobile/scrcpy/pull/2859>
Signed-off-by: Yu-Chen Lin <npes87184@gmail.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
There was only two key injection modes:
- the default one
- the mode with --prefer-text enabled
To prepare the addition of another mode (--raw-key-events), use an enum
instead of a bool.
PR #2831 <https://github.com/Genymobile/scrcpy/pull/2831>
Expose an option to automatically configure and reconnect the device
over TCP/IP, to simplify wireless connection without using adb
explicitly.
There are two variants:
- If a destination address is provided, then scrcpy connects to this
address before starting. The device must listen on the given TCP port
(default is 5555).
- If no destination address is provided, then scrcpy attempts to find
the IP address of the current device (typically connected over USB),
enables TCP/IP mode, then connects to this address before starting.
PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
This will allow to read the property "service.adb.tcp.port" to know if
the TCP/IP mode is enabled on the device, and which listening port is
used.
PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
Depending on the platform and adb versions, the lines output by adb
could end with "\r\r\n". This util function helps to remove all trailing
'\r'.
PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
"adb connect" always returns successfully (with exit code 0), even in
case of failure.
As a workaround, capture its output and check if it starts with
"connected".
PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
In addition to disable stdout and stderr of the child process, add a
flag to disable the error log printed by scrcpy if the command failed.
This will we useful for commands which are expected to fail in some
cases (like "adb disconnect" if the device is not connected).
PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
Let the caller decide if stdout and stderr must be inherited on process
creation, i.e. if stdout and stderr of the child process should be
printed in the scrcpy console.
This allows to get output and errors for specific adb commands depending
on the context.
PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
If SOCK_CLOEXEC exists, then set the flag on socket creation.
Otherwise, use fcntl() (or SetHandleInformation() on Windows) to set the
flag afterwards.
This avoids the sockets to be inherited in child processes.
Refs #2783 <https://github.com/Genymobile/scrcpy/pull/2783>
The options values to configure the server were identified by their
command-line argument index. Now that there are a lot of arguments, many
of them being booleans, it became unreadable and error-prone.
Identify the arguments by a key string instead, and make them optional.
This will also simplify running the server manually for debugging.
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f0
Refs 45b0f8123a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
Pass the information that device clipboard has been set to the key
processor. This avoids the keyprocessor to "guess", and paves the way to
implement a proper acknowledgement mechanism.
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
Tunnel host and port are only meaningful in "adb forward" mode.
They indicate where the client must connect to communicate with the
server. In "adb reverse" mode, the client _listens_, it does not
_connect_.
Refs #2807 <https://github.com/Genymobile/scrcpy/pull/2807>
In "adb forward" mode, by default, scrcpy connects to localhost:PORT,
where PORT is the local port passed to "adb forward". This assumes that
the tunnel is established on the local host with a local adb server
(which is the common case).
For advanced usage, add --tunnel-host and --tunnel-port to force the
connection to a different destination.
Fixes#2801 <https://github.com/Genymobile/scrcpy/issues/2801>
PR #2807 <https://github.com/Genymobile/scrcpy/pull/2807>
Signed-off-by: Romain Vimont <rom@rom1v.com>
Inconditionnally print the scrcpy version first, without using LOGI().
The log level is configured only after parsing the command line
parameters (it may be changed via -V), and command line parsing logs
should not appear before the scrcpy version.
The output of -h/--help was printed on stderr, although it is not an
error.
Printing on stdout allows to pipe the result directly:
scrcpy --help | less
Instead of (in bash):
scrcpy --help |& less
This allows to execute all adb commands with the specific -s parameter,
even if it is not provided by the user.
In practice, calling adb without -s works if there is exactly one device
connected. But some adb commands (for example "adb push" on drag & drop)
could be executed after another device is connected, so the actual
device serial must be known.
The interruptible version of the function to check process success
(sc_process_check_success_intr()) did not accept a close parameter to
avoid a race condition. But as the result, the processes were not closed
at all.
Add a close parameter, and close the process separately to avoid the
race condition.
Interrupt any blocking call on process terminated, like on
server_stop().
This allows to interrupt any blocking accept() with correct
synchronization without additional complexity.
Define server callbacks, start the server asynchronously and listen to
connection events to initialize scrcpy properly.
It will help to simplify the server code, and allows to run the UI event
loop while the server is connecting. In particular, this will allow to
receive SIGINT/Ctrl+C events during connection to interrupt immediately.
Currently, server_stop() is called from the same thread as
server_connect_to(), so interruption may never happen.
This is a step to prepare executing the server from a dedicated thread.
Use the option descriptions to generate the optstring and longopts
parameters for the getopt_long() command.
That way, the options are completely described in a single place.