After the recent changes to the Droidspaces daemon and using custom SELinux policies to fix denials related to Droidspaces during boot,
I can finally confirm that Droidspaces is fully stable on Magisk and Apatch 🥳
Now, only GrapheneOS needs testing..
I can finally confirm that Droidspaces is fully stable on Magisk and Apatch 🥳
Now, only GrapheneOS needs testing..
🔥2👏1💩1
Droidspaces
After the recent changes to the Droidspaces daemon and using custom SELinux policies to fix denials related to Droidspaces during boot, I can finally confirm that Droidspaces is fully stable on Magisk and Apatch 🥳 Now, only GrapheneOS needs testing..
Droidspaces-v5.9.0-daemon-final.apk
14.8 MB
here's the test APK:
1. Install
2. Enable daemon mode
3. Reboot the device
This APK should fix:
1. All the issues related to Magisk/APatch
2.
1. Install
2. Enable daemon mode
3. Reboot the device
This APK should fix:
1. All the issues related to Magisk/APatch
2.
rootfs.img mounting issues in all devices💩1
We just integrated
Here's what that means for you:
Unkillable daemon - even if you
No root manager needed - the daemon runs as UID 0 (root) natively, without relying on Magisk, APatch, or KSU to function.
Clean SELinux - runs under its own permissive domain with no noisy denials.
Symlink mode - developers can place a symlink at
The app just updates the real binary inside
https://github.com/ravindu644/Droidspaces-OSS/commit/9fdca856bd2d296980ab6c0becb490981283a025
@droidspaces
droidspacesd directly into Android's native init system - no KernelSU, Magisk, or APatch needed. No post-fs-data.sh or service.sh scripts either.Here's what that means for you:
Unkillable daemon - even if you
kill -9 it, init brings it right back up automatically.No root manager needed - the daemon runs as UID 0 (root) natively, without relying on Magisk, APatch, or KSU to function.
Clean SELinux - runs under its own permissive domain with no noisy denials.
Symlink mode - developers can place a symlink at
/vendor/bin/droidspaces pointing to /data/local/bin/droidspaces. This means once the vendor image is repacked and shipped, you never need to unpack it again for updates.The app just updates the real binary inside
/data, and init picks it up automatically on the next boot🗿https://github.com/ravindu644/Droidspaces-OSS/commit/9fdca856bd2d296980ab6c0becb490981283a025
@droidspaces
🤯6🔥3❤1💩1
Droidspaces
Photo
Currently, the daemon drops all connections from non-UID0 sockets for security. That means to communicate with the daemon, you must be root, even though theoretically root isn’t required for a client.
This design choice is intended to block malicious connections from managing or running arbitrary commands inside containers as malicious processes.
If your rooting method is compromised, droidspaces, along with all your modules and everything else under the sun, will be compromised too.
Since the daemon uses an abstract socket called @droidspaces, all apps are denied by SELinux anyway, even if I remove the checks. There’s no fix for that without patching SELinux to allow the "untrusted apps" domain to communicate with the socket. But:
We can’t allow untrusted apps to communicate with the daemon via SELinux either. Why? Because that would let any userspace app communicate with the droidspaces app and potentially with any socket in the system, which is extremely dangerous.
The daemon and client are baked into the same droidspaces binary. Also, the binary can directly execute commands if no daemon is found AND it has root. A 3-in-1 solution.
The app requires root anyway to install containers, etc., so even without strict UID checks, the app will partially work.
We can’t use droidspaces as a “command execution environment” for non-root processes to execute root commands needed for the app either. If a vulnerability in droidspaces is exploited, any non-root process could spawn a root shell.
The biggest concern is that the droidspaces binary can execute commands directly inside running containers using the
This is a massive security risk.
So, until someone implements a kernelsu-like solution to “crown” the official droidspaces manager and block connections from everything else, I won’t implement such a feature.
Even if I did, it would overcomplicate the app’s code. Thanks to our 3-in-1 architecture, I didn’t have to touch any app code; the droidspaces binary acts as a client for the daemon if it detects the socket is alive.
This design choice is intended to block malicious connections from managing or running arbitrary commands inside containers as malicious processes.
If your rooting method is compromised, droidspaces, along with all your modules and everything else under the sun, will be compromised too.
Since the daemon uses an abstract socket called @droidspaces, all apps are denied by SELinux anyway, even if I remove the checks. There’s no fix for that without patching SELinux to allow the "untrusted apps" domain to communicate with the socket. But:
We can’t allow untrusted apps to communicate with the daemon via SELinux either. Why? Because that would let any userspace app communicate with the droidspaces app and potentially with any socket in the system, which is extremely dangerous.
The daemon and client are baked into the same droidspaces binary. Also, the binary can directly execute commands if no daemon is found AND it has root. A 3-in-1 solution.
The app requires root anyway to install containers, etc., so even without strict UID checks, the app will partially work.
We can’t use droidspaces as a “command execution environment” for non-root processes to execute root commands needed for the app either. If a vulnerability in droidspaces is exploited, any non-root process could spawn a root shell.
The biggest concern is that the droidspaces binary can execute commands directly inside running containers using the
run command. If any process could connect to the socket, it could enter container shells, execute commands, nuke containers, plant backdoors, etc.This is a massive security risk.
So, until someone implements a kernelsu-like solution to “crown” the official droidspaces manager and block connections from everything else, I won’t implement such a feature.
Even if I did, it would overcomplicate the app’s code. Thanks to our 3-in-1 architecture, I didn’t have to touch any app code; the droidspaces binary acts as a client for the daemon if it detects the socket is alive.
💩1
Droidspaces
Currently, the daemon drops all connections from non-UID0 sockets for security. That means to communicate with the daemon, you must be root, even though theoretically root isn’t required for a client. This design choice is intended to block malicious connections…
Well,
If you really wanted to run a container without root,
You can get help from the upcoming run-at-boot feature baked into the init.
Then,
You can ssh into the container IP if it's NAT or localhost:22 to get a container shell.
This is the secure way of accessing the container without root.
If you really wanted to run a container without root,
You can get help from the upcoming run-at-boot feature baked into the init.
Then,
You can ssh into the container IP if it's NAT or localhost:22 to get a container shell.
This is the secure way of accessing the container without root.
❤2💩1
run-at-boot is integrated into the init level !
You can start containers without KernelSU/Magisk/Apatch or any kind of root solutions from now on 🥳
You can start containers without KernelSU/Magisk/Apatch or any kind of root solutions from now on 🥳
🔥1💩1
Droidspaces
Photo
For clarification, Droidspaces supports two daemon modes:
1. Run the daemon via Magisk/Apatch/KernelSU modules' native
For 99% of users, this solves all issues with Magisk and Apatch. No modifications to your vendor.img are needed.
2. Run the daemon via Android's native init.rc:
- This mode is the most privileged and completely independent of Magisk/Apatch/KernelSU. It even works without any root solutions.
- The daemon is unkillable. If something kills it, init will automatically respawn it.
- Run-at-boot containers are unkillable as well. If droidspacesd gets killed, once init restarts it, run-at-boot will also restart all killed containers.
I don't think Android will ever kill the daemon, but even if it does, all edge cases are covered—thanks to my overthinking 🗿
Notes: If the native init daemon is enabled, the app's toggle will be automatically enabled. The
Everything is backward compatible. You don't even need to worry about daemons if everything is already working for you 🗿
Nothing bad will happen; the binary still supports running everything natively, with or without a daemon 🗣
There are three different logics baked into the same binary:
- Daemon
- Client for the daemon
- Native execution if no daemon is running
1. Run the daemon via Magisk/Apatch/KernelSU modules' native
post-fs-data.sh. By enabling the toggle in the app, you activate the logic in the post-fs-data.sh of the Droidspaces Magisk module to run the daemon on boot. For 99% of users, this solves all issues with Magisk and Apatch. No modifications to your vendor.img are needed.
2. Run the daemon via Android's native init.rc:
- This mode is the most privileged and completely independent of Magisk/Apatch/KernelSU. It even works without any root solutions.
- The daemon is unkillable. If something kills it, init will automatically respawn it.
- Run-at-boot containers are unkillable as well. If droidspacesd gets killed, once init restarts it, run-at-boot will also restart all killed containers.
I don't think Android will ever kill the daemon, but even if it does, all edge cases are covered—thanks to my overthinking 🗿
Notes: If the native init daemon is enabled, the app's toggle will be automatically enabled. The
post-fs-data.sh script will auto-detect if the native init.rc daemon is running, so no collisions will happen if it is.Everything is backward compatible. You don't even need to worry about daemons if everything is already working for you 🗿
Nothing bad will happen; the binary still supports running everything natively, with or without a daemon 🗣
There are three different logics baked into the same binary:
- Daemon
- Client for the daemon
- Native execution if no daemon is running
🗿5💩1
In the latest CI build, we are moving from the
That means even if the binary is run under Magisk’s SELinux domain, we re-execute ourselves to run under our own SELinux domain, completely bypassing
We also have over ~200 lines of custom SELinux rules, specifically written for
https://github.com/ravindu644/Droidspaces-OSS/blob/main/Android/app/src/main/assets/boot-module/etc/droidspaces.te
TL;DR: we have our own permissive SELinux domain, completely independent from Magisk/APatch/KernelSU domains, giving us more freedom.
Also, all processes spawn under our
TL;DR: you can use Droidspaces in SELinux enforcing mode with 0 issues when using the boot-module daemon mode. No need to wire up an
This is the build:
https://github.com/ravindu644/Droidspaces-OSS/actions/runs/23706897589/artifacts/6165166335
According to my testing across 3 phones, everything seems normal for me.
But I suggest you guys test it and report if there are any issues. Especially, I recommend testers to drop a bug report even if there are no issues present, so I can cover all the edge cases.
Here's how:
1. Install
2. Enable daemon mode from settings
3. Reboot the device
4. Generate the bug report and drop it in the chat.
magisk SELinux domain in Magisk/Apatch to our own droidspacesd domain to maintain compatibility with daemon mode in post-fs-data.shThat means even if the binary is run under Magisk’s SELinux domain, we re-execute ourselves to run under our own SELinux domain, completely bypassing
magisk domain restrictions.We also have over ~200 lines of custom SELinux rules, specifically written for
magiskpolicy, which we inject via post-fs-data.sh :)https://github.com/ravindu644/Droidspaces-OSS/blob/main/Android/app/src/main/assets/boot-module/etc/droidspaces.te
TL;DR: we have our own permissive SELinux domain, completely independent from Magisk/APatch/KernelSU domains, giving us more freedom.
Also, all processes spawn under our
droidspacesd domain. Even systemd inherits our permissive domain, meaning no denials can occur.TL;DR: you can use Droidspaces in SELinux enforcing mode with 0 issues when using the boot-module daemon mode. No need to wire up an
init.rc service.This is the build:
https://github.com/ravindu644/Droidspaces-OSS/actions/runs/23706897589/artifacts/6165166335
According to my testing across 3 phones, everything seems normal for me.
But I suggest you guys test it and report if there are any issues. Especially, I recommend testers to drop a bug report even if there are no issues present, so I can cover all the edge cases.
Here's how:
1. Install
2. Enable daemon mode from settings
3. Reboot the device
4. Generate the bug report and drop it in the chat.
💩1
❤1💩1
This media is not supported in your browser
VIEW IN TELEGRAM
Easy Termux-X11 with Droidspaces!
Requirements:
Container:
Termux:
Steps:
01. Open Droidspaces, go to the container configuration menu, enable
02. Start the container.
03. Open the Termux app and type
Now, any tool that requires a GUI can communicate with Termux-X11 for rendering, and the output will be displayed in the
Notes:
@Droidspaces
Requirements:
Container:
sudo apt install mesa-utilsTermux:
pkg install x11-repo && pkg install termux-x11Steps:
01. Open Droidspaces, go to the container configuration menu, enable
Termux-X11, and set the DISPLAY=:0 environment variable, then save the configuration.02. Start the container.
03. Open the Termux app and type
termux-x11 :0.Now, any tool that requires a GUI can communicate with Termux-X11 for rendering, and the output will be displayed in the
Termux-X11 app :)Notes:
:0 is the display number.@Droidspaces
🔥5❤1💩1
Native GPU Acceleration tarball working in Qcom devices 🥳
https://github.com/ravindu644/Droidspaces-rootfs-builder/releases/tag/v20260401-084954
How to use:
1. Download and install the tarball (GUI/base) with HW Access + Termux X11
2. Go to termux and type
3. Done !
https://github.com/ravindu644/Droidspaces-rootfs-builder/releases/tag/v20260401-084954
How to use:
1. Download and install the tarball (GUI/base) with HW Access + Termux X11
2. Go to termux and type
termux-x11 :0 to start the X server3. Done !
🗿3❤1💩1
Get native GPU acceleration on Adreno GPUs with Droidspaces..!
Requirements: Base/XFCE tarball from the latest GitHub release, Latest CI Build
01. Download the latest Base/XFCE tarball from the Droidspaces-rootfs-builder repository.
02. Install it using the Droidspaces app by enabling "Hardware Access" and "Termux X11", and add the environment variable
03. Start the container, then open the Termux app AFTER starting the container and run
04. Done!
Additional: Using GPU acceleration with non-root users
05. Open a container root terminal and create a new user:
06. Add the newly created user to the
07. Add the newly created user to the
08. Log in to your new user and check GPU access with:
To start the XFCE in the XFCE tarballs:
@Droidspaces
Requirements: Base/XFCE tarball from the latest GitHub release, Latest CI Build
01. Download the latest Base/XFCE tarball from the Droidspaces-rootfs-builder repository.
02. Install it using the Droidspaces app by enabling "Hardware Access" and "Termux X11", and add the environment variable
DISPLAY=:0 in the environment variables section.03. Start the container, then open the Termux app AFTER starting the container and run
termux-x11 :0 to start the X server.04. Done!
Additional: Using GPU acceleration with non-root users
05. Open a container root terminal and create a new user:
newuser <username>06. Add the newly created user to the
sudo group: usermod -aG sudo <username>07. Add the newly created user to the
droidspaces-gpu group: usermod -aG droidspaces-gpu <username>08. Log in to your new user and check GPU access with:
glxinfo -B!To start the XFCE in the XFCE tarballs:
dbus-launch --exit-with-session startxfce4@Droidspaces
🔥3💩1🗿1