DROIDLESS / Documentation
Peek under
the hood.
Build it, inspect an APK, and follow the point where Android bytecode meets native desktop UI.
Build & run
The v0.3.0 macOS ARM64 preview includes navigation, persistent notes/preferences, Java collections, APK-local reflection, scheduling, bounded guest workers, native image viewing and modal panels, bounded private file input, staged package-confined output and FileChannel transfers. The archive packages five authored fixtures and three hash-checking public APK fetch helpers. Install Rust 1.95.0 and, on macOS, Xcode Command Line Tools for the Objective-C/AppKit bridge. The runtime build does not require an Android SDK. Read the preview scope notes.
git clone https://github.com/OthmaneBlial/droidless.git
cd droidless
cargo build --release --locked
sh tools/fetch-simple-calculator.sh
target/release/droidless run --size 192x400 \
artifacts/apks/SimpleCalculator.apkThe last command opens native controls on macOS. Headless mode executes the guest and emits the laid-out View tree as JSON. This path has been tested on macOS; Linux has no verified build or native UI yet.
target/release/droidless run --size 192x400 artifacts/apks/SimpleCalculator.apk \
--headless --click 7 --click + --click 5 --click =APK parsing is not a compatibility guarantee. Begin with the demonstrated APKs and treat other apps as experiments.
CLI reference
Use run explicitly, or pass an APK path directly. For example, droidless app.apk starts the runtime. The following commands accept a single APK path.
| Command | Output |
|---|---|
inspect | Package, version, SDK fields, launcher, module counts and declared components. |
manifest | Parsed manifest as JSON. |
dex | DEX versions and class, method, field, string and code-unit counts. |
classes / methods | Class descriptors or method signatures. |
resources | Compiled resource table as JSON. |
inspect-ui | Launch the guest headlessly and print its View tree. |
target/release/droidless inspect artifacts/apks/SimpleCalculator.apk
target/release/droidless run artifacts/apks/SimpleCalculator.apk \
--headless --trace-framework --trace-lifecycle --stats--trace-bytecode prints instruction locations; --trace-methods prints calls; --trace-framework prints compatibility calls; --trace-lifecycle prints lifecycle transitions. --stats or --heap-stats reports parse time, elapsed time, instruction and call counts, and heap statistics. These are diagnostics, not comparative benchmarks. --size WIDTHxHEIGHT sets each logical axis to 128–4096; the default is 420×720.
--advance-ms MILLISECONDS lays out and polls the current frame before advancing the deterministic headless clock and draining due guest callbacks. Native windows use monotonic host time. Replaying the authored timer produces Timer done: 3:
target/release/droidless run --headless --ephemeral fixtures/generated/scheduling.apk \
--click "Start timer" --advance-ms 1500 --advance-ms 1500 --advance-ms 1500--click TEXT replays a View click. --key CHARACTER replays key-down/up events through the guest’s key listener. The following headless sequence produced 2.0; it does not establish KasCalc native keyboard delivery. Native Counter key delivery was checked separately.
sh tools/fetch-kascalc.sh
target/release/droidless run --headless artifacts/apks/KasCalc.apk \
--key 7 --key - --key 5 --key =Current source also provides --back. Escape delivers virtual onBackPressed in a native window, including APK overrides. This authored fixture shows a two-screen round trip:
target/release/droidless run --headless fixtures/generated/intents.apk \
--click "Open detail" --backPreferences persist per package by default. --data-dir APPS_ROOT selects a host-approved root; --ephemeral keeps data in memory only. --input TEXT edits the first enabled visible EditText. This authored fixture saves a note and loads it in a fresh process:
target/release/droidless run --headless --data-dir artifacts/preferences-demo \
fixtures/generated/preferences.apk --click "Edit note" \
--input "This note survives restart" --click "Save note"
target/release/droidless run --headless --data-dir artifacts/preferences-demo \
fixtures/generated/preferences.apkArchitecture
The workspace separates binary formats, execution, and the desktop host into three crates.
droidless-formats- Own parsers for DEX, Android binary XML and
resources.arsc; ZIP/deflate reading uses the Rustzipcrate. The manifest identifies the launcher Activity. droidless-runtime- A DEX register interpreter, handle-based object heap with mark-and-sweep collection, method dispatch, lifecycle callbacks, framework methods, XML inflation and View layout.
droidless- Inspection and runtime commands. On macOS, a small Objective-C bridge renders AppKit views and routes input callbacks into guest methods.
A click invokes the guest’s registered onClick handler or XML callback, executes its bytecode, then redraws the native controls from the resulting View tree. There is no application-specific calculator implementation in the host.
Execution is bounded: the guest call stack is capped at 128 frames, with five million instructions per launch, input, close or message poll. APK parsing rejects unsafe ZIP paths, duplicates, symlinks and oversized inputs without extracting files. These limits do not make the prototype a security sandbox.
There is no audited process isolation, complete bytecode verifier or APK signature trust policy. Inspected Android permissions grant no desktop capabilities; current source supports isolated preferences/SQLite and explicit native folder selection with session-local grants, and returns a fixed virtual value for /proc/self/cmdline; general file, network and native-library APIs are unavailable. Use trusted APKs. Read the full security boundaries.
Compatibility
The target today is a narrow slice of traditional Java Activity applications. Supported operations exist at the level of particular methods and opcodes, not complete Android API classes.
| Area | Current surface |
|---|---|
| Execution | Standalone DEX 035/037/038/039/040 and an interpreter subset covering arithmetic, branches, arrays, fields, objects, calls, dispatch and explicit/common implicit Java throw/catch/finally. Throwable diagnostics retain original DEX call locations and causes across unwind and GC; guest diagnostic overrides still execute. No JIT. |
| Lifecycle | Launcher discovery and basic Application creation. Current source adds explicit same-APK Intents, typed Bundle extras, finish, virtual Back callbacks and a preserved Activity stack. Native transitions and clean root finish are verified in the authored Intents fixture. Application observers add snapshot registration, GC retention and six-event delivery at Activity super calls; fresh native navigation/Back/close records 33 observer calls. Platform fragments support queued add transactions, guest lifecycle callbacks and mounted fragment Views; fragment back stacks remain unsupported. |
| Views | TextView, Button, EditText, LinearLayout and FrameLayout subsets with programmatic color/selector foreground overlays above child controls, native ViewGroup drawing clips with separate input bounds, virtual scrollability queries, bounded adapter-backed GridView, View scroll offsets and child attach/detach and unanimated permanent detached removal through guest callbacks; inherited APK measure/layout callbacks retain XML parameters, per-side padding and closed-drawer geometry; native Notepad mouse selection, title/body editing and restart are verified. Item animations are omitted. General RecyclerView/AndroidX compatibility is not implied; measurement and styling remain approximate. |
| Rich text/XML | Spannable text, SAX callbacks and bounded XML parsing for a real APK serialization path; DTDs are rejected. |
| Resources | Compiled strings and supported layout attributes, plus a bounded binary XML pull cursor and resource-ID-backed typed XML attributes. SwpieView passes its guest vector startup check, attaches its platform lifecycle fragment, constructs its toolbar, GridView and BaseAdapter and opens a native folder chooser. Cancellation exits cleanly; actual folder selection queries and decodes three PNG/JPEG/WebP thumbnails in AppKit. Thumbnail selection now transfers the image stack through guest Parcelable/CREATOR callbacks and opens a decoded full-screen image. Native JPEG/PNG/WebP visits and Escape back to the grid are verified. Touch replay also runs actual swipe navigation and confirmed tap hide/show callbacks. GIF animation, slideshow and lifecycle auto-hide remain unproven. Authored widget checks also cover timed scrolling, manifest application metadata, virtual background dispatch and content descriptions; image labels are verified in native AppKit. Seven non-matrix ImageView scale modes, clipping and per-side padding now render natively. Default configuration wins; full qualifiers, themes, styles and vector drawable inflation remain incomplete. |
| Raster images | Packaged PNG/JPEG/WebP through BitmapFactory resource, stream and byte-array decoding, bounds/sample-size options, ImageView src/bitmap/resource/drawable setters and setImageURI for granted document streams and AppKit NSImageView rendering. An authored fixture verifies four views; bitmap pixel APIs, Canvas and vector/animated drawables remain unsupported. |
| Input evidence | Native Simple Calculator and KasCalc mouse, Counter text-copy/ordinary key delivery, and real keyboard entry into the unmodified Notepad APK have been exercised in AppKit. Counter text evidence uses accessibility value editing. Native UTF-8 clipboard paste is verified in the Preferences fixture; single-pointer MotionEvent dispatch and timed gesture callbacks pass compiled guest checks. Optimized native taps also hide/restore SwpieView controls. Native drag verification, full focus/IME, multi-touch and interception remain incomplete. |
| Options | Flat packaged menu XML, category ordering, resource titles/icons and group state pass compiled checks. Foreground create/prepare callbacks cache and invalidate menus; selection runs guest listeners and Activity fallback with GC, error and stale-input checks. --menu-item TEXT replays enabled visible items. AppKit now bridges foreground options into a native Options menu, with component checks for title ownership, enabled/checked state and action dispatch. Physical menu input remains unverified because UI control could not attach to the running test window. Exact native scope. Generic <view class="…"> layout tags invoke the named DEX constructor and onFinishInflate after child attachment. Live-region mode state is retained; Android accessibility-service announcements remain unsupported. |
| Platform | macOS ARM64 native UI demonstrated. Linux headless path exists; Linux build and native UI are unverified. |
| Preferences | Typed private stores and staged editors, isolated package data, native authored-note save/restart/clear and UTF-8 paste. Apply is synchronous; bounded package-confined file input/output is available, while preference listeners, String sets and unrestricted host paths remain unsupported. |
| SQLite | Bounded SQLiteOpenHelper/statement/transaction, ContentValues update, rawQuery and typed Cursor subset. The unchanged Notepad APK saves two rows and renders both titles after Back and after a fresh process; native AppKit typing and saving were also verified. |
| Java collections | Bounded HashSet/ArrayList/HashMap/basic LinkedHashMap/monitored Hashtable, immediate FIFO queue operations, indexed lists, guest equals, Set/List iterators, native map copying and live read-only Set/List views pass compiled headless conformance. CopyOnWriteArrayList snapshots keep old values across live changes, GC and serial guest worker writes. Canonical Class keys and primitive TYPE metadata resolve. Reentrant snapshot-list write equality, timed queue waiting/iterators, other bulk operations, custom Map copies/views and access-order/eviction behavior remain unsupported. |
| Virtual API profile | Fixed read-only Build.VERSION.SDK_INT = 21, independent of APK and host OS. Compiled checks cover repeated reads, inherited declaring-owner aliases and rejected writes/wrong-kind/type references. This is an API-branch profile; framework coverage remains partial. |
| APK-local reflection | APK-local class lookup, reference constructors and runtime/inherited class annotations execute guest code with access, initialization, argument and cause checks. Inherited field references resolve to their declaring owner; all nine wrapper TYPE fields provide canonical primitive metadata, with final-write faults. Class.toString formats class/interface, primitive/void and array descriptions; the portable contract also passes on Java 17. The canonical APK loader resolves allowed classes without initialization, and Class.asSubclass validates hierarchy casts. Unknown native metadata, custom loaders, reflective method invocation and Field writes remain unsupported; declared APK fields can be read through the bounded Field profile. |
| Scheduled callbacks | Main and prepared worker Handler/Looper queues deliver deferred and delayed guest callbacks, cancel by identity and retain payloads through GC. Worker loop callbacks preserve managed waits and support quit/quitSafely; routing, ordering, exception recovery and bounded dispatch pass compiled checks. Authored wait/deliver/cancel controls pass headless replay, and native host finish cancels blocked callbacks cleanly. Manual native clicks on those new controls remain unverified. Native authored timer/finish and deterministic replay verified. Java Timer/TimerTask adds one guest worker per Timer, long/Date deadlines, fixed-delay/fixed-rate schedules, cancellation/purge and bounded catch-up; compiled checks verify serial blocking, GC, faults, capacity and main Handler UI delivery. Single/fixed/cached executor pools queue work on reusable guest Threads. Callable/Runnable Futures retain actual values and causes, support cancellation and worker deadline waits, and report real shutdown state. Worker Thread.sleep and Thread.join retain frames, values and monitors until their deadline, interruption or actual target termination. The authored Sleep, join and finish action passes automated native host delivery through a main Handler and clean Activity shutdown; manual native input on this action remains unverified. Bounded deferred guest workers execute DEX on a serial shared-heap host executor. Headless queue/monitor waits, interruption and main Handler results are verified; the native Start worker action also delivers its main-thread result and closes cleanly. Exact methods and limits. |
| Activity results and folders | Same-APK result callbacks preserve request codes, snapshot data at finish and defer delivery for stopped callers. The authored native APK returns child results and actual NSOpenPanel folder choices; grants are session-local and URI parsing grants nothing. SwpieView loads three native thumbnails, opens selected images in its full-screen Activity and returns with Escape. Bounded Parcel reconstruction isolates mutable launch/result extras; shallow Bundle/Intent copies retain object values. The authored contract checks callbacks, mutation/GC, cycles, malformed data and cleanup. Binder/file descriptors, Java serialization bytes and custom loaders remain unsupported. Custom Serializable objects can remain as same-runtime references across bounded snapshots. Bounded document queries and read-only streams are supported; writes, other providers and persistent grants remain unsupported. Exact scope. |
| Outside scope | Main/native-bridge blocking waits, general wait/notify, nested Looper pumps/priority, parallel execution, Timer finalization and JVM process-liveness parity, AndroidX, Compose, modern Kotlin patterns, JNI/native libraries, services, general implicit/external intents, general file APIs, networking, full Android graphics and Linux GUI. |
Explicit throws and common implicit Java faults are catchable: integer/long zero division, null access/throw, negative array sizes, array bounds/store errors, casts, string bounds and numeric parse failures propagate guest Throwable objects. Compiled tests cover 17 fault paths, typed hierarchy matching, cross-frame catches, catch-all/finally and getMessage.
Inherited interface assignability and reference-array covariance are exercised by compiled Java tests. Failed class initialization persists: non-Error causes are wrapped in ExceptionInInitializerError, existing Error subclasses propagate directly, and later access throws NoClassDefFoundError. Causes remain rooted through garbage collection.
Concurrent initialization and initialization of default-method superinterfaces remain unsupported. Instruction/field/method checks are not a complete Java type verifier. Unsupported APIs, malformed instructions and resource ceilings remain terminal diagnostics; unsupported methods/opcodes retain method, DEX module and PC context.
Multi-DEX APKs are parsed; split-APK installation is unsupported. Newer invoke forms, container DEX 041 and optimized/quickened DEX are rejected. The resource and layout implementation does not reproduce the complete Android rendering system. Read the exact opcode groups and known ceilings.
Evidence
swiftugandan’s Simple Calculator 1.0 supplies the independently built, unmodified public APK shown here. The fetch helper pins its commit and verifies:
7c1adc93607c8511a3abd379f74765747d2ae72fb70c4ff5c471f13e94b98921Native macOS button clicks demonstrated 7 + 5 = → 12, 8 × 8 = → 64 and 9 / 3 = → 3. The screenshot below captures the first result. The logical viewport is 192×400; table stretching, gradients and Android theme fidelity remain incomplete.

Seven headless cases verify arithmetic, decimals, multiple digits and clear through this APK’s own callbacks. Native Escape dispatches Back and exits with status 0 after pause/stop/destroy. This runtime is included in v0.3.0; the calculator is fetched unchanged from upstream. The public APK is neither modified nor redistributed.
The macOS executable’s linked-library inspection showed AppKit, QuartzCore, Foundation and system libraries, with no Android runtime. No emulator or Android subprocess fallback participates in execution.
Separately, ten headless KasCalc cases passed through its own listeners: addition, multiplication, division, subtraction, decimals, square/cube roots, backspace, sign and reset. Headless KeyEvent replay produced 2.0 for 7 − 5 =.
Automated tests also execute the unmodified SmallestAPK Hello World app and a separately labeled DROIDLESS-authored Counter fixture. In the current native Counter build, setting the text field to Bonjour and clicking Copy input displayed Bonjour through the APK callback. An ordinary native letter key reached its OnKeyListener, displaying key 45 for the logical q supplied by the French host keyboard layout; the consumed key did not enter the field.
Closing native Counter emitted onPause, onStop and onDestroy, then exited with status 0. The current KasCalc build was rechecked with native 7 + 5 = → 12.0 and the same clean close lifecycle. Native text evidence covers accessibility value editing and ordinary key delivery. The earlier Counter clipboard attempt timed out. Subsequent Preferences verification below proves native UTF-8 paste; full focus and IME behavior remain unverified.
In the authored Intents fixture, native Home text editing survived a Detail round trip. Escape restored the same text and updated title; another Activity intercepted Back in its own bytecode. Finishing the root ended the process with status 0. Tests separately check typed extras, copying, exact lifecycle order, retained Views across GC and inactive finish.
The authored Preferences fixture additionally verifies native paste, save and a fresh runtime displaying the stored UTF-8 note; clear remains cleared after restart. Compiled headless collection checks cover ordered/indexed lists, duplicates/nulls, guest equality, iteration, live read-only views, Class identity and GC retention. The same list/read-only view, snapshot-list, native map-copy and immediate queue contracts also pass on desktop Java 17. Queue checks cover FIFO/duplicates, full capacity, null rejection, guest equality and inherited override dispatch. The Scheduling fixture now also checks resumable worker take/put waits; timed waits and main/native-bridge waiting remain unsupported. The authored Reflection and Primitive contracts verify initialization/access errors, inherited field aliases and all nine primitive TYPE identities; the same contracts pass on desktop Java 17. The compiled ThrowableContract also checks retained explicit/implicit fault locations, cause cycles, GC, refreshed traces and diagnostic callback failures; its separate desktop Java driver passes. Printed locations use DEX PCs; source lines, StackTraceElement arrays, suppression and stream/writer overloads remain unsupported. This is not an Android reference run. The unmodified Notepad 1.0.0 APK now opens its Notes screen and note editor in the headless runtime. The 390 × 844 View tree contains two editable fields; typing Hello, desktop updates the first. Its SHA-256 is pinned and checked by tools/fetch-notepad.sh. Two notes now persist in the APK's private SQLite database. The Notes screen renders both after Back and after a fresh process restart. The local replay also reopens an existing note, updates its title and multiline body, retains the same row ID and restores both fields in a fresh editor process. Separate AppKit checks select an existing row with the mouse, type both fields, save through Escape and reopen the exact edits in a fresh native process; the original row ID is retained and both processes exit cleanly. A separate malformed-body replay now logs the real SAX fault, shows the APK’s own !ERROR! marker and preserves the raw stored row when opened in a fresh process. XML metacharacters still do not round-trip through its serializer; this error path has headless evidence only. Visual fidelity remains unverified. Open the illustrated View-tree preview; it is not a native screenshot.
sh tools/fetch-notepad.sh
target/release/droidless run --headless --ephemeral --size 390x844 \
--click "+" --input "Hello, desktop" artifacts/apks/notepad-v1.0.0.apkFrom the repository root, python3 tools/compatibility.py verifies both Notepad SQLite rows, list refresh and existing-note title/body edits after restart. The body probe excludes XML metacharacters; see the verification record for that limit.
The original Notepad options menu loads through its own AppCompat code. Headless Delete now returns to Notes, removes only the chosen SQLite row, and preserves the survivor’s original ID, title and body through restart and reopen. Snackbar measurement and its original translation/alpha start callbacks execute. Clock-driven View property frames, cancellation, callback GC and fault cleanup pass a compiled contract. Timed headless replay shows the original message and UNDO label at 250 ms, then removes the Snackbar after another 3000+250 ms while retaining the exact surviving row. Headless Undo also restores title/body with a fresh auto-increment ID, keeps the survivor exact and reopens both fields after restart; the old timeout causes no further change. Native menu input, Delete/Undo and timed feedback remain unverified. Current checks and exact scope.
Headless navigation taps reveal Notepad’s original drawer frame at 100 ms and complete its settlement at 1000 ms. Back closes the drawer while keeping Notes and both exact note rows. Shared rendering runs the APK’s computeScroll callbacks; explicit View focus requests now retain real ownership and execute guest callbacks. Compiled checks cover descendant policies, callback GC, removal and adapter refresh. Physical drawer input and full focus/IME remain unverified. Selecting Create or edit folders opens Edit Folders and binds the original editor/button listener; Back retains both exact note rows. Installed AppCompat inflater callbacks construct the actual guest AppCompatImageButton. Cloning, merged callbacks, attributes, ViewStubs, GC and fault cleanup pass compiled checks. Starting creation now passes descendant coordinates, resource backgrounds, TextPaint and child drawable-state callbacks. Tapping the original editor opens Done and writes exactly one named folder in SQLite. The new row now renders through themed text appearance and sized attachment callbacks. A fresh process reopens the visible folder, and Back restores both exact notes. Saved-row attachment now invokes its actual TextInputLayout binding callback. Headless focus and pending input complete; a fresh process discards an unconfirmed name and retains both exact notes and the saved folder. Native font family/style assignment passes component checks on buttons, labels and editors. AppKit first-responder gains now request actual guest focus. Component checks cover key-view traversal, retained selection, refused focus and callback failures. The shared dispatcher also creates and renames folders in optimized replay; unconfirmed input is discarded on restart. Complete bidirectional focus and physical folder input remain unverified. Host focus evidence. TextWatcher and scalar ValueAnimator callbacks execute real DEX; ARGB and retained Paint shadow state support label calculations. Paint/TextPaint ascent/descent use the same actual font selection as AppKit controls. Original rename confirmation completes; the same folder ID/new name survive restart and Back with both exact notes. Headless folder deletion is verified below; physical folder input and Android font parity remain unverified. Current folder rename and font-metrics evidence.
The authored Images APK packages 96×64 PNG, JPEG and WebP assets. Its original DEX checks BitmapFactory resource bounds and sample sizing, stream and byte-array decoding, ImageView resource/bitmap/drawable assignment, and XML src. Four ImageViews displayed the images in an actual AppKit window. This is fixture evidence. Separately, the unmodified SwpieView APK now opens a selected folder, displays three thumbnails, opens JPEG/PNG/WebP images in its full-screen Activity and returns with Escape. FrameLayout gravity now places its bottom controls below the toolbar. Root touch replay diagnoses its slideshow listener: DOWN starts a Timer, UP cancels it, and a held DOWN reaches rejected worker UI access. Its own Parcelable callbacks transfer the image stack; touch replay verifies exact next/previous image bytes and first/last bounds. Native taps hide and restore controls; native drag verification remains pending. GIF animation and slideshow remain unproven.

The authored Scheduling APK now also verifies native delayed callbacks: Start displays Waiting for timer, then Timer done: 3 after three callbacks. Cancel before the first deadline remains cancelled; Finish later closes through guest code with status 0. Headless checks cover ordering, Message/Handler overrides, token identity, GC, faults and limits. The desktop Java comparisons cover unstarted metadata/manual run, the pure WorkerContract and portable Timer validation/serial tasks. Compiled TimerTask checks also verify Date deadlines, bounded fixed-rate catch-up, cancellation/purge, GC, blocked task ordering and failure cleanup; results reach the UI through a main Handler. The optimized native action reaches Background timer done: 3; restart/cancel stays cancelled beyond later deadlines at a 420 × 720 viewport. The compiled Future contract checks reusable pools, result/cause retention, waits, cancellation and shutdown; its portable entry point passes on desktop Java. Native Start future worker waits for input, Deliver future input shows Future result: payload through the main Handler, and Cancel future worker stays cancelled. Normal close exits 0. Compiled headless worker checks also verify identity, FIFO waits, interruption, monitor ownership, main Handler result delivery and GC across pauses. A native Start worker click now delivers the complete result in accessibility state and closes with status 0; its long visible label clips at the 360 × 340 test viewport. Worker sleep/join checks cover deadlines, interrupts, argument errors, monitor retention and GC; the portable contract also passes on desktop Java. The automated native Sleep, join and finish action checks main Handler delivery after AppKit opens, then closes with status 0. Its result painting before immediate finish and manual native input remain unverified. Scheduling scope and reproduction.

After the managed-frame change, the fresh release passes automated calculator/timer replays. Native window automation could not attach to the running calculator, so its desktop interaction and clean-close recheck remains incomplete for this increment. The captures record earlier native milestones. Exact verification scope.
Both calculators are interactive subsets: menus, gestures, complete visual fidelity and every numeric edge case remain untested. No Android reference differential run, Linux build/UI validation or broad compatibility is claimed. Full verification record · APK evidence catalog.
🪟 Dialogs now render into separate native panels with independent View trees, guest lifecycle/input, nested Back and queued listeners. Authored DEX checks cover bounds, focus, GC and failure recovery; AppKit checks cover real panels and control callbacks. Headless replay now displays the original folder-delete title, message and guest-bound buttons. Cancel retains the folder ID/name; confirmed deletion, restart and Back preserve both exact notes. Physical public-dialog input remains unverified. Current evidence and limits ↗
💾 Bounded FileOutputStream writes stage up to 64 MiB before atomic commit; input/output FileChannels share stream position and support bounded transfers. The unchanged Notepad APK writes a byte-exact SQLite backup and restores a tampered copy, with every Note/Folder row recovered and visible after relaunch. Current source maps its post-restore System.exit(0) to CLI status 0; the tagged v0.3.0 archive retains the earlier guest-error boundary. Exact file-input limits · Release scope.
Development & local checks
All CI runs locally. The script checks formatting, compilation, tests, Clippy warnings and the release build. No GitHub Actions workflow is installed.
sh tools/ci.shParser tests reject truncated DEX/XML/APK data, invalid indexes, unsafe ZIP paths and duplicate ZIP entries. Runtime tests exercise real D8-generated arithmetic, wide values, arrays/covariance, inherited interface dispatch, explicit/implicit exceptions across 17 fault paths, catch-all/finally, lifecycle, resources, XML layouts and input callbacks.
Managed DEX calls now pause/resume with their caller/callee frames retained. Compiled checks collect between each instruction and verify reference/wide returns, catches/finally, diagnostic stacks and limits. The normal FrameContract also passes on desktop Java; native bridges and class initialization remain synchronous within a step. Bounded workers now use these frames for queue/monitor waits; suspension across a synchronous native bridge/initializer remains unsupported. Frame semantics.
Failed-initialization tests cover wrapping versus Error propagation, subsequent NoClassDefFoundError, and cause retention across garbage collection.
Local CI passes 150 Rust tests, checks native font family/style assignment and matching ascent/descent on three AppKit control types, verifies native editor focus/selection/refusal, separate dialog panels/control callbacks, foreground/clipping paint and full accessibility labels for shortened text, and also runs 4,096 seeded APK/DEX/XML/resource mutations without panics. The compatibility replay checks the authored XML pull parser, PNG/JPEG/WebP fixture and four ImageViews, plus grid item clicks, adapter refresh, child result delivery, Back cancellation, three selected-folder images and SwpieView full-screen viewing/Back through guest Parcelable reconstruction, image swipes and confirmed tap hide/show. The authored touch contract also covers coordinate translation, capture, click fallback, double taps, show/long press, scroll/fling, cancellation and callback GC/error cleanup. Native photo-grid clicks, disabled items and refresh are verified; viewport recycling and touch scrolling remain unsupported. This is deterministic smoke coverage; a continuous coverage-guided fuzz campaign remains future work. GitHub Actions are disabled.
The independent calculator replay is a separate local check. It verifies both fetched APK digests and tests actual headless TextView/EditText results:
sh tools/fetch-kascalc.sh
sh tools/fetch-simple-calculator.sh
python3 tools/compatibility.pyNormal runtime tests use checked-in authored APKs and require no Android SDK. Rebuilding them requires Android SDK compiler tools. A development macOS app bundle can be assembled separately:
sh tools/macos-app.shThe bundle is unsigned and intended for development. The project is Apache-2.0; third-party fixtures retain their upstream licenses. Read the source and repository documentation .
Source documents
Download the original project documents for the exact implementation scope, evidence and next milestones. Roadmap items are future objectives.