Skip to content

About

A high-performance Android storage analyzer that bypasses MTP using a native C++ daemon, a Rust TCP bridge, and a React Treemap UI.

Resources

Stars

134 stars

Watchers

1 watching

Forks

Latest commit

Β 

History

34 Commits

Folders and files

Repository files navigation

SocketSweep Logo

SocketSweep

See what's eating your Android storage in seconds, not minutes.

License: GPL 3.0 Tauri v2 React 19 C++17 Rust
Sponsor


😀 The Problem

Ever plugged your Android phone into your PC to figure out what's eating all your storage?

Here's what happens with the standard USB connection (MTP):

  • You open the phone in File Explorer / Finder
  • Click on a folder with lots of files
  • "Calculating size..." β€” hangs for 4+ minutes
  • Eventually shows sizes, but navigating is painfully slow
  • Trying to find large files? Good luck scrolling through hundreds of folders one by one

This is because MTP (Media Transfer Protocol) β€” the protocol your OS uses to talk to Android over USB β€” was designed in 2008 for MP3 players. It transfers file metadata one item at a time, with no caching, no parallel requests, and no way to do a fast recursive scan. It was never built for phones with 100GB+ of photos, videos, and apps.

SocketSweep bypasses MTP entirely.


⚑ How Fast?

Full /sdcard scan on a Samsung Galaxy S24 Ultra (256GB) with ~47,000 files:

SocketSweep: ~6-15 seconds β€” full interactive treemap ready to explore.

Scan time varies depending on device load (background apps, media indexing, thermal state). Best case was 6.9 seconds with a warm cache and minimal background activity.

For comparison, doing the same thing over MTP (plugging in the phone and browsing via Windows Explorer or Finder) typically involves minutes of "Calculating size..." freezes, and macOS Finder doesn't even show folder sizes at all.

Proper side-by-side benchmarks against OpenMTP and other tools are coming soon.


πŸ“Έ What It Looks Like

SocketSweep Dashboard SocketSweep Treemap

Left: Connection Dashboard | Right: Interactive Treemap β€” click any block to drill down


πŸš€ How to Use

1. Download

Download SocketSweep v1.1.1

Platform Download
πŸͺŸ Windows Installer (.exe) Β· Enterprise (.msi)
🍎 macOS (Apple Silicon) Disk Image (.dmg)
🐧 Linux AppImage · .deb

Arch/AUR note: The socketsweep-bin package is currently unmaintained and its checksum check fails until an adopter bumps it to v1.1.1. In the meantime, Arch users can install the .deb directly: sudo pacman -U SocketSweep_1.1.1_amd64.deb

macOS note: Since the build is ad-hoc signed, run this once after installing:

xattr -cr /Applications/SocketSweep.app

2. Enable USB Debugging on your phone

Go to Settings β†’ About Phone β†’ tap "Build Number" 7 times to unlock Developer Options. Then go to Settings β†’ Developer Options β†’ enable "USB Debugging".

3. Plug in and scan

  1. Connect your phone via USB cable
  2. Open SocketSweep
  3. Click Connect β€” the app will automatically push the daemon to your phone and set everything up
  4. Click Scan β€” your full storage treemap loads in seconds
  5. Click on any block in the treemap to drill down. Found something huge you don't need? Delete it right from the app.

That's it. No apps to install on your phone, no Wi-Fi setup, no root required.


🧠 How It Works (The Short Version)

Instead of going through MTP, SocketSweep does something completely different:

  1. Pushes a tiny C++ program (~1MB) to your phone via ADB
  2. That program scans the filesystem directly on the phone using native POSIX calls β€” this is why it's so fast (no MTP bottleneck)
  3. Streams the results back to your PC over a TCP socket through the USB cable
  4. Renders an interactive treemap in a React frontend so you can visually see what's taking space

The architecture was inspired by scrcpy β€” the "push a native binary via ADB, communicate over a local socket" pattern.

Each connection authenticates with a fresh 256-bit session secret before the daemon accepts a command. The secret reaches the phone through a shell-owned startup file with mode 0600; the daemon reads and removes that file before listening. The app and daemon must use the same protocol version.


πŸ— Architecture (For Developers)

SocketSweep has three layers:

flowchart TB
    subgraph Host["Host Desktop"]
        UI["React + Recharts<br>Interactive Dashboard"]
        Bridge["Rust / Tauri Backend<br>Command Orchestrator"]
        
        UI <--> Bridge
    end

    subgraph Transport["ADB Protocol"]
        Tunnel["ADB Port Forwarding<br>TCP:5050 -> TCP:5050"]
    end

    subgraph Device["Android Device"]
        Daemon["C++17 Daemon<br>Headless Socket Server"]
        Storage[("POSIX Filesystem<br>/sdcard")]
        
        Daemon <--> Storage
    end

    Bridge <--> Tunnel
    Tunnel <--> Daemon
Loading

Interaction Lifecycle

sequenceDiagram
    participant U as React UI
    participant R as Rust (Tauri)
    participant A as ADB Shell
    participant D as C++ Daemon (Android)
    
    %% Connect Phase
    U->>R: invoke("init_daemon")
    R->>A: pkill daemon (Cleanup)
    R->>A: push daemon /data/local/tmp
    R->>A: appops set MANAGE_EXTERNAL_STORAGE allow
    R->>A: Write private startup secret, launch daemon
    R->>A: adb forward tcp:5050 tcp:5050
    R->>D: AUTH session secret (on every connection)
    R->>D: Ping-Retry Loop (150ms)
    D-->>R: ACK Connection
    R-->>U: Connected!
    
    %% Scan Phase
    U->>R: invoke("run_scan", { path: "/sdcard" })
    R->>D: TCP Send: `SCAN /sdcard\n`
    Note over D: Recursive Fast POSIX Traversal
    D-->>R: Stream Large JSON Tree
    R-->>U: Parse & Render Treemap
    
    %% Delete Phase
    U->>R: invoke("delete_item", { path })
    R->>D: TCP Send: `DELETE /sdcard/... \n`
    Note over D: Descriptor-relative traversal and unlinkat<br/>Child symlinks are never followed
    D-->>R: {"status":"ok"}
    R-->>U: Update UI / Rescan
Loading

πŸ”§ Development Setup (Building from Source)

Prerequisites

  1. Node.js (v18+)
  2. Rust (v1.70+ with Cargo)
  3. Android NDK (v26d or newer)
  4. Android SDK / ADB installed and added to your system $PATH.

1. Compile the C++ Daemon

Cross-compile the daemon for aarch64-linux-android:

# Set your NDK path
export NDK=/path/to/your/android-ndk-r26d

# Build the daemon
cd engine
bash ./build.sh

This generates the stripped daemon binary in the engine/ directory and copies it into src-tauri/bin/daemon, which Tauri bundles. Rebuild after changing the daemon so local development uses the current protocol.

2. Install Frontend Dependencies

cd ..
npm install

3. Run the App

npm run tauri dev

Ensure your Android device is plugged in via USB and USB Debugging is enabled.

4. Run regression tests

# macOS/Linux: compiles the host daemon and uses disposable local files
python3 -m unittest discover -s tests -v

# Build the frontend first when testing from a clean checkout
npm run build
cargo test --locked --manifest-path src-tauri/Cargo.toml --lib

The line-based protocol preserves spaces in filenames. Paths containing a newline, carriage return, or null byte are rejected before sending, so they cannot cause a different file to be deleted. Scan responses containing invalid UTF-8 filenames are also rejected rather than replacing filename bytes.

Deletion is anchored to the directory opened for the successful scan. Child directories are opened one component at a time without following symlinks, and removal uses those handles instead of resolving the original full path again. Detected changes to roots or directory entries stop deletion. Parent symlinks and traversal into another filesystem are rejected. /sdcard root aliases remain supported. Recursive deletion has a depth limit of 64 directories.

Deletion is not transactional: concurrent filesystem changes or permission errors can stop it after some entries were removed. Rescan before retrying. An operation already in progress uses the opened directory identities; renaming a path cannot redirect it into a different directory through a new symlink.


πŸ›  Troubleshooting

"0 Files" or Missing Folders on Android 11+

Android 11 introduced Scoped Storage, restricting file access. SocketSweep automatically tries to bypass this via:

adb shell appops set com.android.shell MANAGE_EXTERNAL_STORAGE allow

If scanning still shows nothing, check if your OEM requires extra toggles (e.g., Xiaomi needs "USB Debugging (Security settings)" enabled).

Samsung Auto Blocker

If you're on a Samsung device and USB Debugging is greyed out, you probably have Auto Blocker enabled. Go to Settings β†’ Security β†’ Auto Blocker and turn it off. Auto Blocker disables USB Debugging entirely, so no ADB-based tool (including SocketSweep) will work with it on. It's off by default β€” you'd only have this issue if you manually turned it on.

AppImage Fails to Launch on Arch Linux (Wayland)

If the AppImage crashes or fails to start on Arch Linux under a Wayland session, launch it with the Wayland client library preloaded:

LD_PRELOAD=/usr/lib/libwayland-client.so ./SocketSweep.AppImage

See this issue for more context.

Daemon Fails to Start

If you get Permission denied, make sure the daemon is being pushed to /data/local/tmp/. Modern Android blocks execution from /sdcard/. SocketSweep handles this automatically.


πŸ’– Support This Project

If SocketSweep saved you from the nightmare of MTP, consider supporting its development:

Sponsor on GitHub Β Β  PayPal

πŸ“„ License

SocketSweep is released under the GNU General Public License v3.0. See the LICENSE file for more details.


πŸ‘‹ Author

Built by Vishnu Srivatsava. Inspired by the architecture of scrcpy. Currently looking for Backend / Systems Engineering roles. Feel free to reach out on LinkedIn or via email.

About

A high-performance Android storage analyzer that bypasses MTP using a native C++ daemon, a Rust TCP bridge, and a React Treemap UI.

Resources

Stars

134 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages