Skip to content

Direct Overlay ​

Direct Overlay is Jugg's alternate overlay-write path when a device has not yet reached the online Apply Changes ready state. It writes the incremental overlay directly into the app sandbox, while the outer deployment flow remains responsible for startup, restart, test execution, and completion.

Direct Overlay conditions ​

ScenarioCurrent supportDeployment strategy
Device is not ready, but history and cache matchSupportedWrites the overlay directly into the app sandbox
Android O or later, with compatible Apply Changes prerequisitesSupportedUses run-as to write into the app sandbox
Class, resource, or asset change with no run-as success marker, an out-of-range UID, or a mismatched SELinux labelSupported when the permission probe succeedsUses a fixed ordinary-shell, root-adbd, or device-supported non-interactive-su command form against the real data directory
run-as, ordinary shell, root adbd, and non-interactive su are all unavailableSupported for compat payloads; other payloads convert to compat deploy firstStages the compat payload under the app-specific external files directory for the app to import on its next start, without pushing any JVMTI agent
Apply Changes startup agent must be prepared in advanceSupportedThe Direct Overlay path pushes the Android Studio startup agent
Overlay ID does not match the expected valueDoes not force a writeSwitches to recovery or reinstallation
The writer fails after modifying the overlayDoes not fall back to old Apply ChangesPrevents continued deployment from a partially committed state

IMPORTANT

Direct Overlay replaces only the overlay update transport. It does not take over the complete deployment lifecycle. Starting the app, restarting it, running androidTest, and committing history remain responsibilities of the outer deployment flow.

How it takes effect ​

text
The device is not ready and Direct Overlay is allowed
  -> Read the deployment cache and expected overlay ID
  -> Check the device-side overlay ID
  -> Build an overlay ZIP payload
  -> Transfer it to the device through ADB
  -> Atomically update the overlay in the sandbox as the target app
  -> Write the new overlay ID last
  -> Update the deployment cache

The Recover stage checks history, cache, and device-side overlay state. Before writing, it validates the device-side overlay ID against at least the cache. The new overlay ID is committed last. If writing fails after the overlay directory has changed, Jugg treats the state as dirty and does not attempt a false fallback to old Apply Changes.

When run-as, the UID, or the SELinux label does not meet Android Studio Deployer prerequisites, the same deployment reuses one sandbox executor with a fixed permission mode. This prevents the overlay, startup agent, and JVMTI Hot Reload steps from switching paths after root state changes.

Direct permission modes repair SELinux labels separately for data files and Agent .so files: overlay data inherits the app cache directory's dynamic categories, while .so files use a type the app process can execute. Additional output from the repair tools does not change the write command's success result.

Boundaries ​

Direct Overlay requires all of the following:

  • The user or caller allows Direct Overlay.
  • The device is not in the regular ready-to-deploy state.
  • A deployment cache exists and the overlay checkpoint can be validated.
  • Deployment data is non-empty and does not represent an install.
  • The device OS version meets the requirement and the app sandbox is writable through the selected run-as, ordinary-shell, root-adbd, or non-interactive-su mode.

When run-as, the UID, or the SELinux label is incompatible, Jugg can deliver classes, resources, and assets directly. Pure method-body changes can be replaced online. On Android 11 or later, resource, asset, and mixed code/resource changes refresh resources in the current process and recreate the Activity, falling back to an app restart if the refresh fails. Android 8–10 and compatible deployment retain resource paths that require a process restart. Manifest still uses APK update and installation; native libraries enter an overlay and load after an app restart when SO hot update is enabled, or use an APK update when disabled. A missing deployment cache causes an explicit failure.

When the ordinary shell, root adbd, and non-interactive su are unavailable too, Jugg stops trying to write the app sandbox: ordinary class, resource, and asset changes are converted to compat deploy first, and the compat payload is staged under the shell-writable, app-readable /sdcard/Android/data/<package>/files/jugg/rootless-compat/<requestId>/. The app is restarted once and locates the request through Context.getExternalFilesDir(null) before importing code_cache/.overlay during early startup. This path never pushes, copies, or attaches a JVMTI agent, and it does not advance the deployment cache, deploy history, or file state until the app confirms the import; a failed or timed-out import keeps the previous overlay and fails explicitly.