Skip to content

Dev#2

Open
superturtlee wants to merge 166 commits into
superturtlee:devfrom
ravindu644:dev
Open

Dev#2
superturtlee wants to merge 166 commits into
superturtlee:devfrom
ravindu644:dev

Conversation

@superturtlee

Copy link
Copy Markdown
Owner

No description provided.

404-GCross and others added 30 commits June 5, 2026 15:47
* 微调 README_CN.md 与社区支持设备文档措辞

* 修复 GPU-Acceleration_CN 缺少 Rootfs 仓库引用链接

* 翻译 community-supported-devices_CN 新增的 WildKernels OnePlus 设备表格(96行)

* 翻译 community-supported-devices_CN 中 none→无、Working→正常运行

* 翻译社区支持设备状态选项:正常运行/部分可用/不可用

* 修复社区支持设备文档措辞

* 微调社区支持设备文档措辞

* 微调社区支持设备文档措辞

* 微调社区支持设备文档措辞

* 微调社区支持设备文档措辞

* 微调社区支持设备文档措辞

* 微调社区支持设备文档措辞
- monitor, virgl, pulse: explicitly enter droidspacesd via new
  ds_selinux_enter_domain() -- permissive, zero enforced denials
- x11: stays on untrusted_app_27 (app_process requires it);
  dyntransition() loses dead applied_ctx output param
- untrusted_app_27 first in domain trial order to match real Termux
- sepolicy: scope fd/fifo_file rules to untrusted_app_27 (not untrusted_app);
  add audioserver/mediaserver fd use for PulseAudio binder path
Patch default.pa at runtime: load aaudio before always-sink, disable
module-sles-sink and module-console-kit. Add --use-pid-file=false and
--disallow-exit to prevent futex deadlock on Android userdata flock.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…ndencies and configure PulseAudio for Droidspaces

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…ough

OPOST on the outer line discipline transforms \n->\r\n, corrupting
escape sequences from tmux/vim/claude-code before they reach the user.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
vendor 4.9 devpts patches return EINVAL/EIO on newinstance mounts,
causing silent PTY alloc failure; kernel auto-unlocks when needed

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
… buf

- signalfd(SIGCHLD) replaces 100ms poll-waitpid busy loop in handle_session
- signalfd(SIGWINCH) replaces signal handler + 200ms epoll timeout in client
- drop redundant poll() probe before recv_frame_hdr in client frame loop
- shrink cmdline log buffer from 16KB to 512B stack allocation

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
all four functions were identical modulo which ds_config bool field
they tested. collapse into one offsetof-based scanner; keep thin
compat wrappers so existing call sites are unchanged

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…own_lines

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
3 identical ~25-line stop functions (x11/virgl/pulse) collapsed to
one-liner wrappers; kill/wait/unlink logic lives in one place now

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Move Android-specific sources (android, x11, virgl, pulseaudio) into
src/android/, network sources (network, netlink, iptables, dhcp) into
src/net/, and all headers into src/include/.

Redundant prefixes/suffixes dropped: ds_ and -android stripped where
the subdirectory name already conveys the context.

Update Makefile SRCS paths, -I flag (now -Isrc/include), VERSION grep
path, and add mkdir -p to the compile rule for object subdirs.
Update src/socketd/Makefile -I and fix api_server.cpp's relative
Support NixOS-specific su path to run su correctly in NixOS containers.
…stale runtime configuration

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Currently translated at 100.0% (467 of 467 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (467 of 467 strings)



Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/zh_Hant/
Translation: Droidspaces/Strings

Co-authored-by: Jung Chi Wang <snowwolf725@gmail.com>
Co-authored-by: MengHanLOVE <2193438288@qq.com>
Inject libskcodec.so into LD_PRELOAD (lib64 > lib priority) to fix
module-sles-sink dlopen failure on One UI 6.1+; install libandroid-stub
and disable module-suspend-on-idle in setup-termux.sh to fix PA futex hang.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Signed-off-by: ravindu644 <droidcasts@protonmail.com>
replace scattered getuid() checks with a single gate after daemon proxy;
rename is_stateless_cmd -> is_no_root_cmd, add 'check' to exempt list

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Signed-off-by: ravindu644 <droidcasts@protonmail.com>
replace blocking write_all(master) with non-blocking write + dynamic wbuf;
flush via EPOLLOUT, suspend conn EPOLLIN at 192KB, resume at 64KB

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Signed-off-by: ravindu644 <droidcasts@protonmail.com>
* build: add patched BusyBox as submodule

* build: enable socketd backend bridge by default
Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…y applied post-extract fixes

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Acquire PARTIAL_WAKE_LOCK then fire ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
(API 23+); fallback to ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS for OEMs
that block the direct dialog (MIUI etc.). Add manifest permission.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Add receive/send timeouts to accepted socketd backend bridge
connections so a partially written request cannot block the privileged
bridge indefinitely.

Also replace the bridge-specific same-EUID authorization rule with the
same peer authorization model used by the main daemon: allow root, or
allow peers that are members of the droidspaces group. This keeps the
backend bridge aligned with the existing Droidspaces local privilege
boundary instead of granting access to every process running under the
same UID.
ravindu644 and others added 30 commits July 18, 2026 17:12
ds_ipt_remove_portforwards() Pass 3 interpolates container_ip into four
sh -c commands -- the only shell-command path in the networking code.
container_ip is already strictly validated to 172.28.x.x at every ingest
point, so it is not currently exploitable, but the function itself did no
local check. Re-validate it with inet_pton() at the point of use and skip
the shell sweep on anything that is not a plain IPv4 literal, so no shell
metacharacter can reach sh even if an unvalidated caller is ever added.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
nl_nest_begin() returns NULL when appending would exceed the buffer, but
callers passed the result straight to nl_nest_end(), which dereferenced it
to fix up rta_len -- a NULL write on buffer exhaustion. Unreachable today
(names are short and fixed) but a latent trap if buffers or inputs change.
Guard nl_nest_end() so every caller is covered; the kernel then rejects
the incomplete message rather than the process crashing.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
RTA_OK() validates an attribute's declared length but not that its
payload is a full 4 bytes, so the *(int*)/*(uint32_t*)RTA_DATA reads for
IFLA_MASTER, RTA_TABLE/OIF/PRIORITY and FRA_TABLE/PRIORITY/FWMARK/FWMASK
could read up to 3 bytes past a truncated attribute. The data source is
the host kernel (always full-width), so this is defensive hardening.

Add nl_rta_u32() which returns 0 for a short attribute and reads via
memcpy (also avoiding unaligned access), and route all such reads through
it; guard the equivalent read in network.c's route monitor inline.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
ds_metadata_sync() reconstructs the host mount sidecar from
/run/droidspaces/mount read inside the container's own root, then saves it
via save_mount_path(); that value later feeds unmount_rootfs_img() /
umount2() on the host. A compromised container could plant an arbitrary
path there and make the host unmount an unrelated mount point.

A legitimate image mount is deterministically written as
DS_IMG_MOUNT_ROOT_UNIVERSAL/<sanitized-name> (i.e. /mnt/Droidspaces/<name>,
from find_available_mountpoint), so require the marker to match that exact
path for this container and ignore anything else. Exact match also
prevents a container from pointing at another container's mount.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…ridge

Delete the #if 0 / #endif payload-drain block sitting in the connection
dispatch hot path, and replace the lingering 'could be an alias via
__attribute__' TODO on socketd_ntoh64 with a plain explanatory comment.
No behavioral change.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…path

The !booted branch freed cfg and then jumped to the cleanup: block, which
dereferences cfg (cleanup_container_resources) and frees it again. It was
only safe because the free helpers NULL their pointers and cleanup reads
inline scalars, but it is a read-after-free / double-free waiting for the
first freed field that cleanup touches. Let the single cleanup: block own
all teardown.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The new_blob malloc-failure path returned -ENOMEM directly, bypassing the
free(cur_base) at the function tail. On an EAGAIN refetch iteration
cur_base owns a get_table()-allocated blob, so that early return leaked
it. Free it before returning, matching the cleanup every other exit path
already performs.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
pidfile_to_mountfile() and pidfile_to_initfile() were byte-identical apart
from the extension macro. Extract pidfile_to_sidecar(pidfile, ext, ...)
and make both thin wrappers over it. As a side benefit the extension is
now passed as a "%s" argument rather than as snprintf's format string,
removing the latent format-string footgun if an extension macro ever
gained a percent sign.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
nuke_pulse_config() forked and exec'd /system/bin/rm -rf to delete the
stale runtime dir. The tree already has remove_recursive() (nftw-based),
so replace the whole fork/exec/waitpid dance with a single call - no
external binary dependency and no child plumbing.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The three record-append helpers (container, image, core-event) were
byte-identical except the element type: same capacity doubling, wrap
check, DS_SOCKETD_MAX_PAYLOAD bound, realloc and zero-fill. Factor the
growth into socketd_grow_array(records, count, cap, elem_size); each
append now just grows then does its typed copy. Same behavior, one place
to get the bounds math right.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
pulse_child_wrapper, virgl_child_wrapper and xserver_child_wrapper each
repeated the same four signal(...SIG_IGN) calls plus ds_oom_protect().
Extract ds_daemon_child_preamble() and call it from all three. The
per-helper SELinux handling (which genuinely differs) stays local.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
ds_setup_pulse_socket and ds_setup_virgl_socket ran the identical dance:
build the DS_TERMUX_TMP_OLDROOT/<leaf> source path, stat it, bind-mount via
ds_bind_mount_socket owned by the socket's uid, log, and setenv. Extract
ds_bridge_termux_socket(leaf, dst, env_key, env_val, label); both setups
are now a single call. The X11 bridge is left as-is: it additionally
creates and chmods the container socket dir and logs differently.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The main daemon and the socketd bridge each implemented SO_PEERCRED +
group-membership + PID-namespace authorization independently, and the two
copies had already drifted (the daemon's getgrouplist handling was fixed
in isolation). Extract ds_peer_authorized(fd, group_name) as the single
implementation and call it from both.

This also upgrades the bridge, which previously denied any user in more
than 64 groups, to the same realloc-and-retry getgrouplist handling the
daemon uses. Behavior is otherwise unchanged.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The nav hint padding used strlen(hint) - 8, where the magic 8 hand-cancels
the extra bytes of the four 3-byte UTF-8 arrow glyphs. Any change to the
hint wording broke the alignment. Count display columns directly (bytes
that are not UTF-8 continuation bytes) instead.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
ds_config_free() freed binds/env/unknown lines but not tx11_extra_flags /
virgl_extra_flags, which main freed separately after calling it - so every
other ds_config_free() caller leaked those two strings. Free (and NULL)
them inside ds_config_free(), drop main's separate frees, and replace the
hand-rolled disk_cfg field frees in ds_config_save() with ds_config_free()
(which also releases disk_cfg's env vars, previously leaked). Single owner
now, no double free (the reset path already NULLs the fields).

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…_page

print_page redefined printf to the pager wrapper (#define printf p_printf
... #undef printf) so its 143 page-body calls routed through the pager.
Shadowing a libc function by macro is surprising and fragile. Rename those
calls to p_printf() directly and drop the macro; the pager wrapper and its
g_* scroll/dry-run state are unchanged, so output and paging behavior are
identical.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
When running a command as another user, run_in_rootfs() joins argv[] with
spaces into a single su -c string. su's shell then re-splits on those
spaces, so 'run ... -- rm "a b"' became 'rm a b' (three words). Quote
each argument as a single-quoted shell word (with the '\'' idiom for
embedded quotes) so word boundaries survive. The single-argument case is
unchanged: it is still passed verbatim so a caller can hand su a full
shell command string.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
count_running_containers() and show_containers() both open the pids dir
and, per entry, resolve the container name + pidfile and prune stale
pidfiles with the same unlink + remove_mount_path + remove_init_type
sequence. Extract resolve_scanned_container() and prune_stale_pidfile()
and use them in both. Each function keeps its own control flow (counting
vs the dynamic array with realloc/OOM handling), so behavior is
unchanged.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Four opcode handlers (PING, CAPABILITIES, INFO, LIST_IMAGES) repeated the
same 'discard the unused payload, reply BAD_REQUEST on short read, return'
block verbatim. Wrap it in socketd_drain_payload() returning 0/-1 so each
site is a single guarded call. The optional-payload reads (LIST_CONTAINERS,
POLL_EVENTS) and the one mandatory read (INSPECT) are left as-is since
their conditions differ.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The route monitor thread died on some internal container reboots, leaving
WiFi<->mobile handoff broken until a full stop/start. Two compounding
causes:

1. route_monitor_loop treated any recv() error other than EINTR/EAGAIN as
   fatal and broke out of the loop. A reboot's veth teardown/recreate emits
   a burst of netlink multicast messages that can overflow the socket
   receive buffer (ENOBUFS) - a recoverable condition. Now ENOBUFS triggers
   a resync (do_uplink_reprobe) and continues; a 0-length read is likewise
   non-fatal unless stopping; genuinely fatal errors are logged before
   exiting. This alone keeps the single monitor instance alive across the
   reboot, as intended.

2. On any self-exit the loop never cleared g_route_monitor_started, so the
   per-cycle ds_net_start_route_monitor() call no-op'd on a stale flag and
   the monitor never came back. Now self-exit clears started (keeping the
   thread joinable), and start reaps a self-exited thread before spawning a
   replacement. stop now gates its join on a new needs_join flag so a thread
   that already self-exited is still reaped rather than leaked.

The failure was intermittent (only when the burst overflowed), which is why
handoff worked after most reboots and silently stopped after the unlucky
ones.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
…drop logs

remove_ds_rules() ignored the return value of every raw-socket
remove_matching_rules() call, and a failed IPT_SO_SET_REPLACE commit was
swallowed (only the EAGAIN retry was logged). Confirmed on-device: with no
container running (empty pids dir, empty /mnt/Droidspaces, no ds-v* veth),
all four rules the last cleanup claimed to drop were still installed in the
host iptables - they leaked on every container stop while the log said they
were removed. The insert path uses the same syscall and works, so the raw
removal blob is the culprit; the iptables binary '-D' removes them cleanly.

- Check each raw removal's return; on failure (or when no raw socket is
  available) fall back to 'iptables -D', which deletes reliably. The four
  binary forms are now defined once and driven from a small table instead of
  being duplicated in the no-socket branch.
- Log the setsockopt errno on the non-EAGAIN failure so the exact kernel
  rejection is visible (for a later fix of the raw fast path).
- The per-rule build-phase log now says 'matched' instead of 'dropping', so
  it no longer claims a removal that has not committed.

Raw fast-path blob fix left as a follow-up; the binary fallback guarantees
cleanup in the meantime.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The raw-socket rule removal failed on-device with errno ELOOP (Symbolic
link loop). In netfilter's IPT_SO_SET_REPLACE path, translate_table() ->
mark_source_chains() walks each hook's chain following xt_standard_target
verdicts: a negative verdict is a built-in (ACCEPT/DROP/RETURN/policy),
while a non-negative verdict is an ABSOLUTE byte offset to a jump target,
validated by xt_find_jump_offset(). remove_matching_rules() re-based
hook_entry/underflow after deleting a rule but never the jump verdicts, so
every verdict pointing past the removed rule kept its stale (now too-high)
offset; the kernel could no longer resolve the jump and rejected the whole
replace with ELOOP. That is why removal silently failed on Android, where
netd installs many jump-laden custom chains.

Add fixup_jump_targets_removed(), the removal twin of the existing
insert-side fixup_jump_targets(): walk the rebuilt blob and subtract, from
each non-negative verdict, the bytes removed before its target offset
(old_offsets[k] -> removed_before[k], the same arrays the hook/underflow
fixup uses). The binary iptables -D fallback stays as belt-and-suspenders.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
The swipe-gesture change routed every tab action through
pagerState.animateScrollToPage(). That is a positional scroll, so tapping
a non-adjacent tab (e.g. Home -> Control Panel) slid the pager across the
intervening page (Containers) instead of switching directly, and animating
across the heavy intermediate/target pages - none pre-composed - stuttered.

Use pagerState.scrollToPage() for the tab-bar taps, the Home screen's
navigate-to-Containers/Control-Panel buttons, and the back handler. That
jumps straight to the target page with no intervening scroll (no
pass-through, no slide-while-composing jank), restoring the pre-swipe feel
for taps while swipe gestures keep working via the pager's native drag.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
* Use latest-release permalink for kernel download

The build repository now publishes the kernel zip with a fixed filename
(`raphael_YAAP-sixteen_KernelSU-by-xx.zip`). This lets us use GitHub's
`/releases/latest/download/` permalink, so the link automatically points
to the newest build without manual updates.

* Use latest-release permalink for kernel download

The build repository now publishes the kernel zip with a fixed filename
(`raphael_YAAP-sixteen_KernelSU-by-xx.zip`). This lets us use GitHub's
`/releases/latest/download/` permalink, so the link automatically points
to the newest build without manual updates.
Inspect the selected tarball (without extracting) and confirm it
contains the core top-level directories every Linux rootfs has (bin,
sbin, etc, usr) before extraction. This prevents users from installing
arbitrary archives such as photo backups or random tarballs.

The validator lists the archive with busybox tar and bails out as soon
as all markers are found, so a valid rootfs is confirmed without
decompressing the whole image. Runs for both directory and sparse-image
installs; on failure the install aborts and cleans up.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Add static app shortcuts for Containers, Panel and Settings, shown when
long-pressing the launcher icon. Each deep-links into the same screen as
the in-app navigation: Containers/Panel select their tab on the reused
Home screen, and Settings is pushed on top of it. Routing is gated on
completed onboarding, and a launched-from-history guard prevents the
shortcut from re-firing when the app is reopened from Recents.

Shortcut icons reuse the tab glyphs (Storage, Dashboard, Settings gear)
on the app's launcher-background disc so they stay legible on any
launcher.

Signed-off-by: ravindu644 <droidcasts@protonmail.com>
Currently translated at 76.5% (394 of 515 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (3 of 3 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (515 of 515 strings)




Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/ro/
Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ro/
Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/zh_Hans/
Translation: Droidspaces/Plurals
Translation: Droidspaces/Strings

Co-authored-by: PixelThrived <me@pixelthrived.com>
Co-authored-by: seriaTvT <63958697+seriaTvT@users.noreply.github.com>
The monitor never read the console PTY master in background mode, only
foreground did (via console_monitor_loop). Once a container's init wrote
past the ~64 KiB PTY buffer, /dev/console blocked forever in
n_tty_write and the whole container wedged permanently.

Add the master to the monitor's existing heartbeat poll loop and drain
it continuously, appending output to a per-container console log. This
both fixes the deadlock and recovers previously-lost background boot
logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.