Skip to content

Add Android on-device debugging support#5012

Merged
shai-almog merged 4 commits into
masterfrom
android-on-device-debugging
May 23, 2026
Merged

Add Android on-device debugging support#5012
shai-almog merged 4 commits into
masterfrom
android-on-device-debugging

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Mirrors the iOS on-device-debug flow from #4999 for Android. Since Dalvik/ART already speaks JDWP, no desktop proxy is needed — the Maven plugin just orchestrates adb.

  • Build hint android.onDeviceDebug=true flips the manifest to debuggable="true" and disables R8/proguard; release builds are unaffected.
  • cn1:android-on-device-debugging Mojo locates adb, optionally adb connects a wireless device, installs the APK, sets the debug-app for wait-for-attach, launches the Activity, forwards JDWP onto localhost:5005, and streams logcat --pid=<pid> to the console with a [device] prefix.
  • cn1:buildAndroidOnDeviceDebug wrapper force-sets the hint and triggers the standard android-device cloud build.
  • Archetype ships two IntelliJ run configs in the existing On-Device Debug folder: CN1 Android On-Device Debug (Maven) and CN1 Attach Android (Remote JVM Debug, localhost:5005).
  • New developer-guide chapter On-Device-Debugging-Android.asciidoc covers the IntelliJ quick start, wireless debugging (both the Android 11+ adb pair flow and the legacy adb tcpip flow), the Maven CLI flow, source resolution for both codenameone-core and codenameone-android jars, and a troubleshooting section. The new hint is documented in Advanced-Topics-Under-The-Hood.asciidoc alongside the existing android.debug / android.release rows.

JNI C/C++ is explicitly out of scope (JDWP doesn't speak it); the chapter notes that Android Studio's LLDB can attach to the same process alongside this JDWP session for NDK code.

Test plan

  • Generate a fresh project from cn1app-archetype. Confirm .idea/runConfigurations/CN1_Android_OnDeviceDebug.xml and CN1_Attach_Android.xml appear in the On-Device Debug folder, and common/codenameone_settings.properties has the commented android.onDeviceDebug=true line.
  • Uncomment the hint, run mvn cn1:buildAndroidOnDeviceDebug, install the APK on a USB-connected device, run CN1 Android On-Device Debug, then attach via CN1 Attach Android. Set a breakpoint in user code and confirm it fires after resume.
  • Repeat against the Android emulator.
  • Repeat against a wireless device using -Dcn1.android.onDeviceDebug.wireless=<ip:port>.
  • Set a breakpoint in -android module code (a native interface impl) and confirm it fires.
  • Set a breakpoint in com.codename1.impl.android.AndroidImplementation and confirm source resolution against the codenameone-android sources jar.
  • Confirm logcat lines stream into the CN1 Android On-Device Debug run window with a [device] prefix.
  • Sanity check: build a release APK (no hint set) and confirm the manifest is not debuggable="true".

🤖 Generated with Claude Code

Mirrors the iOS on-device-debug flow from #4999 for Android, taking
advantage of the fact that Dalvik/ART already speaks JDWP — no
desktop proxy needed. The Codename One Maven plugin orchestrates adb:
install the APK, mark it as the debug-app, launch the Activity, poll
for the PID, forward JDWP onto localhost, and tail logcat. The
existing IntelliJ workflow extends: there is now a CN1 Android
On-Device Debug + CN1 Attach Android pair under the same On-Device
Debug folder as the iOS configs.

Pieces:
- AndroidGradleBuilder parses a new android.onDeviceDebug build hint
  that flips the generated manifest to debuggable=true and disables
  R8/proguard so symbols and locals survive the build. Release builds
  (anything without the hint) are unaffected.
- cn1:android-on-device-debugging — new Mojo that drives the adb
  session end-to-end, with autodetection of adb from ANDROID_HOME /
  ANDROID_SDK_ROOT / standard Studio SDK paths / $PATH, optional
  adb connect <ip:port> for wireless devices (Android 11+
  adb pair / adb connect and legacy adb tcpip both covered), APK
  autodetection from target/, am set-debug-app -w for wait-for-
  attach, and a logcat stream prefixed [device] for the lifetime of
  the session. Cleans up adb forward on shutdown.
- cn1:buildAndroidOnDeviceDebug — wrapper that force-sets the hint
  and invokes the existing android-device cloud build, so the IDE
  menu has a one-click entry that doesn't depend on the project's
  codenameone_settings.properties.

Archetype:
- common/codenameone_settings.properties carries the new hint
  commented out, next to the existing ios.onDeviceDebug.* lines.
- .idea/runConfigurations/CN1_Android_OnDeviceDebug.xml — Maven run
  config that invokes the new Mojo from the project root.
- .idea/runConfigurations/CN1_Attach_Android.xml — Remote JVM Debug
  to localhost:5005, scoped to the -common module.

Developer guide:
- New On-Device-Debugging-Android.asciidoc chapter: IntelliJ quick
  start, wireless debugging (both Android 11+ and legacy paths),
  Maven CLI flow, flag table, source-resolution for both
  codenameone-core and codenameone-android sources jars, and
  troubleshooting. Explicitly calls out that JNI C/C++ is out of
  scope (use Android Studio + LLDB for that, can run alongside).
- Advanced-Topics-Under-The-Hood gets an android.onDeviceDebug
  entry next to the existing android.debug / android.release rows.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 23, 2026

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 23, 2026

Compared 20 screenshots: 20 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

Three gates failed on the original push:

- SpotBugs DE_MIGHT_IGNORE in AndroidOnDeviceDebuggingMojo's shutdown
  hook (catch-all swallowed every Exception silently). Narrow the
  catch to MojoFailureException — the only checked exception runAdb
  can throw — and surface the message to stderr so a stuck adb
  forward is at least visible at shutdown. Process.destroy() doesn't
  declare a checked exception, so the surrounding try/catch is no
  longer needed for that call.
- Vale (Microsoft.Contractions + Microsoft.Adverbs) on
  On-Device-Debugging-Android.adoc: "it is" → "it's"; drop "rarely"
  by rewriting the command-line-flags lead sentence; drop "silently"
  from the breakpoint-not-firing troubleshooter.
- LanguageTool typo flags: "codepath" → "code path" in the
  waitForAttach=false note; allowlist "adb", "logcat", and "pidof"
  in languagetool-accept.txt under a new "Android tooling" section
  so future Android docs don't re-trip the same rule.
Two follow-ups to the initial hint binding:

- Force off android.enableProguard alongside disableR8. ProGuard runs
  on the non-Gradle-8 legacy path, and even on Gradle 8 it can layer
  on top of R8 when android.enableProguard=true; either way the user
  loses method names and locals. The hint now disables both
  obfuscators so symbols survive the build regardless of which
  Gradle line the project is on.
- Force android.release=false and android.debug=true. Android's
  manifest is shared between the release and debug variants, so
  android:debuggable="true" propagates to both. The cloud build also
  produces both APKs by default (android.release defaults to true).
  Without this pin, a stray hint left in codenameone_settings.properties
  would silently ship a release-signed APK marked debuggable=true —
  a serious security problem since any device that side-loads it
  would be exposing a JDWP socket. Pinning to debug-only means the
  release APK is simply not produced when the hint is on, and the
  developer guide row for the hint now spells that out.

Companion change in the BuildDaemon's AndroidGradleBuilder (separate
repo) applies the same guard for the cloud build path.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 23, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 23, 2026

Compared 110 screenshots: 110 matched.

Native Android coverage

  • 📊 Line coverage: 11.91% (6763/56788 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.67% (34010/351672), branch 4.18% (1393/33359), complexity 5.21% (1669/32007), method 9.06% (1357/14973), class 14.77% (303/2051)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 11.91% (6763/56788 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.67% (34010/351672), branch 4.18% (1393/33359), complexity 5.21% (1669/32007), method 9.06% (1357/14973), class 14.77% (303/2051)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 760.000 ms
Base64 CN1 encode 203.000 ms
Base64 encode ratio (CN1/native) 0.267x (73.3% faster)
Base64 native decode 971.000 ms
Base64 CN1 decode 364.000 ms
Base64 decode ratio (CN1/native) 0.375x (62.5% faster)
Image encode benchmark status skipped (SIMD unsupported)

Vale Microsoft.Contractions flagged the expanded row on the second CI
run: "cannot" → "can't", "that is" → "that's". Same fix pattern as
the earlier batch of contraction tweaks in the Android chapter.
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 23, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 198 seconds

Build and Run Timing

Metric Duration
Simulator Boot 57000 ms
Simulator Boot (Run) 5000 ms
App Install 13000 ms
App Launch 5000 ms
Test Execution 289000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 408.000 ms
Base64 CN1 encode 1234.000 ms
Base64 encode ratio (CN1/native) 3.025x (202.5% slower)
Base64 native decode 282.000 ms
Base64 CN1 decode 850.000 ms
Base64 decode ratio (CN1/native) 3.014x (201.4% slower)
Base64 SIMD encode 420.000 ms
Base64 encode ratio (SIMD/native) 1.029x (2.9% slower)
Base64 encode ratio (SIMD/CN1) 0.340x (66.0% faster)
Base64 SIMD decode 393.000 ms
Base64 decode ratio (SIMD/native) 1.394x (39.4% slower)
Base64 decode ratio (SIMD/CN1) 0.462x (53.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 59.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.169x (83.1% faster)
Image applyMask (SIMD off) 174.000 ms
Image applyMask (SIMD on) 53.000 ms
Image applyMask ratio (SIMD on/off) 0.305x (69.5% faster)
Image modifyAlpha (SIMD off) 113.000 ms
Image modifyAlpha (SIMD on) 71.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.628x (37.2% faster)
Image modifyAlpha removeColor (SIMD off) 200.000 ms
Image modifyAlpha removeColor (SIMD on) 66.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.330x (67.0% faster)
Image PNG encode (SIMD off) 930.000 ms
Image PNG encode (SIMD on) 758.000 ms
Image PNG encode ratio (SIMD on/off) 0.815x (18.5% faster)
Image JPEG encode 426.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 23, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 198 seconds

Build and Run Timing

Metric Duration
Simulator Boot 60000 ms
Simulator Boot (Run) 1000 ms
App Install 11000 ms
App Launch 4000 ms
Test Execution 257000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 382.000 ms
Base64 CN1 encode 1343.000 ms
Base64 encode ratio (CN1/native) 3.516x (251.6% slower)
Base64 native decode 297.000 ms
Base64 CN1 decode 1026.000 ms
Base64 decode ratio (CN1/native) 3.455x (245.5% slower)
Base64 SIMD encode 437.000 ms
Base64 encode ratio (SIMD/native) 1.144x (14.4% slower)
Base64 encode ratio (SIMD/CN1) 0.325x (67.5% faster)
Base64 SIMD decode 423.000 ms
Base64 decode ratio (SIMD/native) 1.424x (42.4% slower)
Base64 decode ratio (SIMD/CN1) 0.412x (58.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 58.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.172x (82.8% faster)
Image applyMask (SIMD off) 116.000 ms
Image applyMask (SIMD on) 54.000 ms
Image applyMask ratio (SIMD on/off) 0.466x (53.4% faster)
Image modifyAlpha (SIMD off) 154.000 ms
Image modifyAlpha (SIMD on) 55.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.357x (64.3% faster)
Image modifyAlpha removeColor (SIMD off) 153.000 ms
Image modifyAlpha removeColor (SIMD on) 94.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.614x (38.6% faster)
Image PNG encode (SIMD off) 1196.000 ms
Image PNG encode (SIMD on) 836.000 ms
Image PNG encode ratio (SIMD on/off) 0.699x (30.1% faster)
Image JPEG encode 568.000 ms

@shai-almog shai-almog merged commit 2ca4ab3 into master May 23, 2026
29 of 31 checks passed
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.

1 participant