Skip to content

ADFA-2778: ensure binaries in build-tools are executable after installation#916

Merged
itsaky-adfa merged 4 commits intostagefrom
fix/ADFA-2778
Feb 9, 2026
Merged

ADFA-2778: ensure binaries in build-tools are executable after installation#916
itsaky-adfa merged 4 commits intostagefrom
fix/ADFA-2778

Conversation

@itsaky-adfa
Copy link
Contributor

@itsaky-adfa itsaky-adfa commented Feb 3, 2026

See ADFA-2778 for more details.

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>
Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>
@itsaky-adfa itsaky-adfa requested review from a team and jomen-adfa February 3, 2026 09:29
@itsaky-adfa itsaky-adfa self-assigned this Feb 3, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Release Notes - ADFA-2778: Ensure Binaries in Build-Tools Are Executable After Installation

Overview

This PR enhances the build-tools installation process to ensure that multiple binary executables have the correct permissions after installation, improving reliability of the build process.

Key Changes

  • Expanded executable binary coverage: Extended executable permission setting from a single AAPT2 binary to 6 build-tools binaries (aapt, aapt2, aidl, dexdump, split-select, zipalign)
  • Added BUILD_TOOLS_VERSION constant: Introduced BUILD_TOOLS_VERSION = "35.0.0" to centralize version management
  • New BUILD_TOOLS_DIR field: Added public BUILD_TOOLS_DIR path variable pointing to {ANDROID_HOME}/build-tools/35.0.0
  • Refactored AAPT2 path: Updated AAPT2 path resolution to use the new BUILD_TOOLS_DIR for consistency
  • Added error logging: Implemented Environment.setExecutable(File) method that logs errors when executable permission setting fails

⚠️ Risks and Best Practices Violations

  1. Hardcoded Build-Tools Version: Version "35.0.0" is hardcoded in the Environment class

    • Risk: If the actual installed build-tools version differs from 35.0.0, binaries will not be found and permissions will fail silently
    • Impact: Build failures due to missing/inaccessible build-tools binaries
    • Recommendation: Consider making the version configurable or detecting the installed version dynamically
  2. No File Existence Validation: The code attempts to set permissions on binaries without verifying they exist

    • Risk: Error logging occurs but installation continues, potentially masking missing binaries until build time
    • Impact: Delayed error detection and confusing error messages later in the build process
  3. Silent Error Continuation: While errors are now logged, the installation process continues even if executable permissions cannot be set

    • Risk: Installation appears successful but binaries remain non-executable, causing cryptic failures at build time
    • Recommendation: Consider treating failed permission setting as a critical error that should halt installation or at least warn the user
  4. No Fallback Strategy: No mechanism to handle cases where setExecutable(true) fails on certain file systems or permission models

    • Risk: On some Android devices or file systems, permission setting may not be possible or may be enforced at runtime
    • Recommendation: Consider adding a verification step or fallback mechanism for permission-restricted environments

Walkthrough

Introduce BUILD_TOOLS_VERSION and BUILD_TOOLS_DIR; update AAPT2 path. Replace single aapt2 executable toggle with a loop that marks multiple build-tool binaries executable. Refactor NDK installation to accept archive/output parameters, add existence check, preserve extraction, PATH update, logging, and cleanup behavior.

Changes

Cohort / File(s) Summary
Build-tools Configuration
common/src/main/java/com/itsaky/androidide/utils/Environment.java
Add BUILD_TOOLS_VERSION = "35.0.0" and BUILD_TOOLS_DIR field; compute tool paths from BUILD_TOOLS_DIR and update AAPT2 reference to use it.
Assets installer / NDK & binaries
app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt
Replace single aapt2 toggle with loop setting executables for aapt, aapt2, aidl, dexdump, split-select, zipalign. Refactor installNdk to accept archiveFile and outputDir, add experiments-gate early return, add archive existence check and debug log, retain tar extraction, PATH update, logging, and archive cleanup; adjust postInstall to iterate binaries and call new installNdk signature.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • ndk installation #880: Modifies BaseAssetsInstaller NDK installation flow and Environment NDK/build-tools fields—strong code-level overlap.
  • ADFA-2179 ndk template #882: Adjusts BaseAssetsInstaller.installNdk including experiments gating—directly related to this PR's NDK refactor.

Suggested reviewers

  • davidschachterADFA

Poem

🐇 I hopped through builds at break of dawn,

Marked aapt and friends so workflows run on,
Pulled out the NDK, untarred with a grin,
Cleaned up the archive, tossed it in bin,
Now tools are ready — time for a sprint!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: ensuring build-tools binaries are executable after installation, which aligns with the core modifications to BaseAssetsInstaller.kt and Environment.java.
Description check ✅ Passed The description references ADFA-2778, which is related to the changeset's objective of ensuring binaries in build-tools are executable after installation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/ADFA-2778

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt`:
- Around line 17-32: The loop in BaseAssetsInstaller.postInstall currently calls
Path.setExecutable(...) and ignores its boolean result so failures are silent;
replace those calls with the existing helper Environment.setExecutable(...)
which logs failures. Update the loop that iterates over the build-tools names
("aapt","aapt2","aidl","dexdump","split-select","zipalign") to call
Environment.setExecutable(Environment.BUILD_TOOLS_DIR.resolve(bin)) for each bin
(keeping the same bin list) so missing files or permission errors are reported.
🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt (1)

58-66: Avoid bash -c to prevent shell parsing/quoting issues.

Build the ProcessBuilder with explicit arguments instead of a shell command string; this is safer and handles paths with spaces correctly.

♻️ Suggested refactor
-				val processBuilder =
-					ProcessBuilder(
-						"${TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH}/bash",
-						"-c",
-						"tar -xJf ${archiveFile.absolutePath} -C ${outputDir.absolutePath} --no-same-owner",
-					).redirectErrorStream(true)
+				val processBuilder =
+					ProcessBuilder(
+						"tar",
+						"-xJf",
+						archiveFile.absolutePath,
+						"-C",
+						outputDir.absolutePath,
+						"--no-same-owner",
+					).redirectErrorStream(true)

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt`:
- Line 65: In BaseAssetsInstaller.postInstall, wrap the call to
processBuilder.start() in a try-catch for IOException so the method logs the
exception and returns false instead of letting the exception propagate; either
move the try-catch inside the existing measureTimeMillis block (so you still
capture elapsed time) or wrap the entire measureTimeMillis call and record
elapsed accordingly, then on catch call the existing logger (or processLogger)
with the error details and return false to match other failure paths.
🧹 Nitpick comments (2)
app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt (2)

82-96: Successful extraction returns false if archive deletion fails.

When exitCode == 0, the return value on line 92 is deleted, so a deletion failure causes the method to report overall failure despite the NDK being successfully extracted. This conflates extraction outcome with cleanup outcome. Consider always returning true after successful extraction and just logging the deletion failure.

♻️ Proposed change
 		return if (exitCode == 0) {
 			logger.debug("Extraction of ${archiveFile.absolutePath} successful took ${elapsed}ms : $result")
 
 			if (archiveFile.exists()) {
 				val deleted = archiveFile.delete()
 				if (deleted) {
 					logger.debug("${archiveFile.absolutePath} deleted successfully.")
 				} else {
-					logger.debug("Failed to delete ${archiveFile.absolutePath}.")
+					logger.warn("Failed to delete ${archiveFile.absolutePath}.")
 				}
-				deleted
-			} else {
-				logger.debug("Archive file not found for deletion.")
-				false
 			}
+			true
 		} else {

77-77: Consider adding a timeout to reader.join().

After destroyForcibly(), the reader thread should eventually terminate, but a bounded join (e.g., reader.join(10_000)) would prevent an indefinite hang in edge cases.

@itsaky-adfa itsaky-adfa merged commit 991d46e into stage Feb 9, 2026
2 checks passed
@itsaky-adfa itsaky-adfa deleted the fix/ADFA-2778 branch February 9, 2026 09:34
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.

2 participants

Comments