Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Scope the c-cpp CodeQL analysis to httrack-android's OWN native code (the JNI
# glue). The vendored httrack engine, coucal, coffeecatch, and libiconv are scanned
# by their own repos, so excluding them here avoids duplicate findings/build time.
name: httrack-android CodeQL config

# NOTE: `paths` applies to ALL languages. Include the Java app sources (for the
# java-kotlin analysis) AND httrack-android's own JNI C (for c-cpp). The vendored
# engine/coffeecatch/libiconv are scanned by their own repos, so exclude them via
# paths-ignore to avoid duplicate findings.
paths:
- app/src/main/java
- app/src/main/jni/htslibjni.c
- app/src/main/jni/htslibjni.h
- app/src/main/jni/htslibjni-private.h

paths-ignore:
- app/src/main/jni/httrack
- app/src/main/jni/coffeecatch
- app/src/main/jni/libiconv-1.17
78 changes: 78 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Android build + test for httrack-android.
# Style follows the httrack repo (least-privilege, concurrency cancel, submodules
# recursive). Phase A is self-contained: it sets up the NDK, cross-compiles OpenSSL
# (cached), vendors libiconv, and ndk-builds the native libs — no pre-published
# image needed. (The docker/ toolchain image + docker-image.yml exist for the later
# Gradle/assemble phase, which needs the full SDK.)
name: Android

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: android-${{ github.ref }}
cancel-in-progress: true

env:
NDK_VERSION: r26d
OPENSSL_VERSION: "3.0.15"

jobs:
# Native-only: proves recursive submodules (incl. nested coucal), libiconv
# vendoring, OpenSSL 3.x, and 64-bit multi-ABI ndk-build. Validated locally for
# arm64-v8a + armeabi-v7a. x86_64 is added once the coffeecatch x86_64 fix lands
# (xroche/coffeecatch#46) — its legacy ucontext block #errors on x86_64.
native:
name: native (ndk-build)
runs-on: ubuntu-24.04
env:
ABIS: arm64-v8a armeabi-v7a
steps:
- uses: actions/checkout@v6
with:
submodules: recursive # MUST be recursive: coucal is nested in httrack
- name: Set up NDK ${{ env.NDK_VERSION }}
id: ndk
uses: nttld/setup-ndk@v1
with:
ndk-version: ${{ env.NDK_VERSION }}
# No local-cache: its restore can yield an NDK missing the clang
# binaries ("clang: No such file or directory"); download fresh each run.
- name: Cache OpenSSL statics
id: ssl-cache
uses: actions/cache@v4
with:
path: /tmp/openssl-android
key: openssl-${{ env.OPENSSL_VERSION }}-ndk-${{ env.NDK_VERSION }}-${{ env.ABIS }}
- name: Build OpenSSL (cache miss)
if: steps.ssl-cache.outputs.cache-hit != 'true'
env:
ANDROID_NDK_ROOT: ${{ steps.ndk.outputs.ndk-path }}
run: OUT=/tmp/openssl-android OPENSSL_VERSION="${OPENSSL_VERSION}" bash docker/build-openssl.sh
- name: Vendor libiconv
run: tools/ci/vendor-libiconv.sh
- name: Stage OpenSSL statics into prebuild/
run: OPENSSL_ANDROID_ROOT=/tmp/openssl-android tools/ci/fetch-openssl-statics.sh
- name: ndk-build
working-directory: app/src/main # contains jni/ — ndk-build auto-discovers Android.mk + Application.mk
run: ${{ steps.ndk.outputs.ndk-path }}/ndk-build APP_ABI="${ABIS}" APP_PLATFORM=android-24 -j"$(nproc)"
- uses: actions/upload-artifact@v4
with:
name: native-libs
path: app/src/main/libs/**/*.so
if-no-files-found: warn

# --- Phases below land with the app modernization (see the plan) ---
#
# assemble: ./gradlew assembleDebug assembleRelease lint — needs the AGP 8 /
# AndroidX migration (Phase 3), and can use the GHCR toolchain image.
#
# emulator-smoke: reactivecircus/android-emulator-runner (x86_64, api 21/29/34),
# installs the APK and runs an instrumented crawl against a local fixture
# server. Needs Phase 4 (storage) + the coffeecatch x86_64 fix.
70 changes: 70 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# CodeQL static analysis: the Java app AND the JNI/C glue. Mirrors the httrack
# repo's codeql.yml (security-extended). c-cpp is scoped to htslibjni*.c via
# .github/codeql/codeql-config.yml so the vendored engine isn't double-scanned.
#
# java-kotlin uses build-mode: none (the app doesn't build under modern Gradle
# until the AGP 8 migration in Phase 3 — no build needed to analyze the source).
# c-cpp builds the JNI glue via a self-contained NDK setup (no pre-published image).
name: CodeQL

on:
push:
branches: [master]
pull_request:
schedule:
- cron: "31 4 * * 1"

permissions:
contents: read

concurrency:
group: codeql-${{ github.ref }}
cancel-in-progress: true

env:
NDK_VERSION: r26d
OPENSSL_VERSION: "3.0.15"

jobs:
analyze:
name: analyze (${{ matrix.language }})
runs-on: ubuntu-24.04
permissions:
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
include:
- { language: java-kotlin, build-mode: none }
- { language: c-cpp, build-mode: manual }
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
queries: security-extended
config-file: ./.github/codeql/codeql-config.yml

# c-cpp only: CodeQL must observe the native compile (arm64-v8a is enough).
- name: Set up NDK ${{ env.NDK_VERSION }}
if: matrix.language == 'c-cpp'
id: ndk
uses: nttld/setup-ndk@v1
with:
ndk-version: ${{ env.NDK_VERSION }}
# No local-cache: its restore can drop the NDK clang binaries.
- name: Build native (c-cpp)
if: matrix.language == 'c-cpp'
env:
ANDROID_NDK_ROOT: ${{ steps.ndk.outputs.ndk-path }}
run: |
OUT=/tmp/openssl-android ABIS=arm64-v8a OPENSSL_VERSION="${OPENSSL_VERSION}" bash docker/build-openssl.sh
tools/ci/vendor-libiconv.sh
OPENSSL_ANDROID_ROOT=/tmp/openssl-android ABIS=arm64-v8a tools/ci/fetch-openssl-statics.sh
( cd app/src/main && "${ANDROID_NDK_ROOT}/ndk-build" APP_ABI=arm64-v8a APP_PLATFORM=android-24 -j"$(nproc)" )

- uses: github/codeql-action/analyze@v3
48 changes: 48 additions & 0 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Build & publish the toolchain image (JDK17 + SDK + NDK + OpenSSL 3.x statics for
# all ABIs) to GHCR, so android.yml/codeql.yml pull a ready image instead of
# recompiling OpenSSL (~10-20 min) every run. First publish is private even for a
# public repo — set the package visibility to public once in repo Packages settings.
name: Toolchain image

on:
push:
branches: [master]
paths: ['docker/**', '.github/workflows/docker-image.yml']
schedule:
- cron: "23 5 * * 1" # weekly: pick up OpenSSL patch releases
workflow_dispatch:

permissions:
contents: read
packages: write

concurrency:
group: image-${{ github.ref }}
cancel-in-progress: true

jobs:
build-push:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: docker
push: true
tags: |
ghcr.io/xroche/httrack-android-build:latest
ghcr.io/xroche/httrack-android-build:${{ github.sha }}
- name: Extract OpenSSL statics (for the container-less emulator job)
run: |
id=$(docker create ghcr.io/xroche/httrack-android-build:latest)
docker cp "$id":/opt/openssl-android ./openssl-android
docker rm "$id"
- uses: actions/upload-artifact@v4
with:
name: openssl-android-statics
path: openssl-android
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ workspace.xml
/app/.externalNativeBuild
/app/build
/app/src/main/jniLibs

# Build inputs fetched/generated by tools/ci (not committed):
# libiconv vendored by tools/ci/vendor-libiconv.sh
# per-ABI OpenSSL statics from the toolchain image / fetch-openssl-statics.sh
/app/src/main/jni/libiconv-1.17/
/app/src/main/prebuild/
2 changes: 1 addition & 1 deletion app/src/main/java/com/httrack/android/jni/HTTrackLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public static boolean loadLibraries() {

try {
/** Load all libraries. **/
final String[] libraries = { "iconv", "httrack", "htsjava", "htslibjni" };
final String[] libraries = { "iconv", "httrack", "htslibjni" };
for (final String lib : libraries) {
Log.d(TAG, "Loading native library " + lib);
System.loadLibrary(lib);
Expand Down
74 changes: 33 additions & 41 deletions app/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@
#

LOCAL_PATH := $(call my-dir)
TARGET_ARCH := arm

# The exidx-merge linker flag is armv7-only (ARM EXIDX sections exist only on
# 32-bit ARM); emitting it on arm64-v8a/x86_64 breaks the link. Gate it per-ABI.
# ndk-build re-includes this file once per ABI with TARGET_ARCH_ABI set.
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
HTS_ARMV7_LDFLAGS := -Wl,--no-merge-exidx-entries
else
HTS_ARMV7_LDFLAGS :=
endif

# <https://github.com/langresser/libiconv-1.15-android/blob/master/Android.mk>
include $(CLEAR_VARS)
Expand All @@ -27,17 +35,17 @@ LOCAL_CFLAGS := \
-DIN_LIBRARY \
-DLIBICONV_PLUG
LOCAL_SRC_FILES := \
libiconv-1.15/libcharset/lib/localcharset.c \
libiconv-1.15/lib/iconv.c \
libiconv-1.15/lib/relocatable.c
libiconv-1.17/libcharset/lib/localcharset.c \
libiconv-1.17/lib/iconv.c \
libiconv-1.17/lib/relocatable.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include/iconv \
$(LOCAL_PATH)/libiconv-1.15/include \
$(LOCAL_PATH)/libiconv-1.15/libcharset \
$(LOCAL_PATH)/libiconv-1.15/lib \
$(LOCAL_PATH)/libiconv-1.15/libcharset/include \
$(LOCAL_PATH)/libiconv-1.15/srclib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libiconv-1.15/include
$(LOCAL_PATH)/libiconv-1.17/include \
$(LOCAL_PATH)/libiconv-1.17/libcharset \
$(LOCAL_PATH)/libiconv-1.17/lib \
$(LOCAL_PATH)/libiconv-1.17/libcharset/include \
$(LOCAL_PATH)/libiconv-1.17/srclib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libiconv-1.17/include
include $(BUILD_SHARED_LIBRARY)

# TODO FIXME: INVESTIGATE THIS
Expand All @@ -52,12 +60,12 @@ include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libcrypto
LOCAL_SRC_FILES := ../prebuild/libcrypto.a
LOCAL_SRC_FILES := ../prebuild/$(TARGET_ARCH_ABI)/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libssl
LOCAL_SRC_FILES := ../prebuild/libssl.a
LOCAL_SRC_FILES := ../prebuild/$(TARGET_ARCH_ABI)/libssl.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
Expand All @@ -72,14 +80,18 @@ LOCAL_SRC_FILES := httrack/src/htscore.c httrack/src/htsparse.c \
httrack/src/htsmd5.c httrack/src/htszlib.c httrack/src/htswrap.c \
httrack/src/htsconcat.c httrack/src/htsmodules.c \
httrack/src/htscharset.c httrack/src/punycode.c \
httrack/src/htsencoding.c httrack/src/md5.c httrack/src/minizip/ioapi.c \
httrack/src/htsencoding.c httrack/src/md5.c \
httrack/src/htssniff.c httrack/src/htsselftest.c \
httrack/src/htscache_selftest.c httrack/src/htsdns_selftest.c \
httrack/src/minizip/ioapi.c \
httrack/src/minizip/mztools.c httrack/src/minizip/unzip.c \
httrack/src/minizip/zip.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/httrack/src \
$(LOCAL_PATH)/httrack/src/coucal \
$(LOCAL_PATH)/../prebuild/$(TARGET_ARCH_ABI)/include \
$(LOCAL_PATH)/include
LOCAL_LDLIBS := -ldl -lz
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../prebuild
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../prebuild/$(TARGET_ARCH_ABI)
LOCAL_SHARED_LIBRARIES := libiconv
LOCAL_STATIC_LIBRARIES := libssl libcrypto
LOCAL_CFLAGS += -O3 -g3 -funwind-tables -fPIC -rdynamic \
Expand All @@ -96,46 +108,26 @@ LOCAL_CFLAGS += -O3 -g3 -funwind-tables -fPIC -rdynamic \
-D_REENTRANT -DPIC -DANDROID -D_ANDROID -DHAVE_CONFIG_H -DINET6 \
-DLIBHTTRACK_EXPORTS -DZLIB_CONST -DHTS_INTHASH_USES_MD5 -DLIBICONV_PLUG\
-DHTS_CRASH_TEST \
-Wl,--no-merge-exidx-entries -Wl,-O1
$(HTS_ARMV7_LDFLAGS) -Wl,-O1
LOCAL_CPPFLAGS += -pthread
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libhtsjava
LOCAL_SRC_FILES := httrack/src/htsjava.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/httrack/src \
$(LOCAL_PATH)/httrack/src/coucal \
$(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../prebuild
LOCAL_SHARED_LIBRARIES := libhttrack
LOCAL_CFLAGS += -O3 -g3 -funwind-tables -fPIC -rdynamic \
-fstrict-aliasing -fvisibility=hidden \
-Wall -Wformat -Wformat-security -Wmultichar -Wwrite-strings -Wcast-qual\
-Wcast-align -Wstrict-prototypes -Wmissing-prototypes \
-Wmissing-declarations -Wdeclaration-after-statement -Wpointer-arith \
-Wsequence-point -Wnested-externs -Wparentheses -Winit-self \
-Wunused-but-set-parameter -Waddress -Wuninitialized -Wformat=2 \
-Wformat-nonliteral -Wmissing-parameter-type -Wold-style-definition \
-Wignored-qualifiers -Wstrict-aliasing -Wno-sign-compare \
-Wno-type-limits -Wno-missing-field-initializers -Wno-cast-align \
-Wno-nested-externs \
-D_REENTRANT -DPIC -DANDROID -D_ANDROID -DHAVE_CONFIG_H -DINET6 \
-DLIBHTTRACK_EXPORTS -DZLIB_CONST -DHTS_INTHASH_USES_MD5 -DLIBICONV_PLUG\
-DHTS_CRASH_TEST \
-Wl,--no-merge-exidx-entries -Wl,-O1
LOCAL_CPPFLAGS += -pthread
include $(BUILD_SHARED_LIBRARY)
# NOTE: the old `libhtsjava` module (httrack/src/htsjava.c) was dropped — the
# engine removed htsjava.c (the desktop Java-applet parser bridge) after 3.49-2,
# and nothing on Android used it. "htsjava" is likewise removed from
# HTTrackLib.loadLibraries().

include $(CLEAR_VARS)
LOCAL_MODULE := htslibjni
LOCAL_SRC_FILES := htslibjni.c coffeecatch/coffeecatch.c coffeecatch/coffeejni.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/httrack/src \
$(LOCAL_PATH)/httrack/src/coucal \
$(LOCAL_PATH)/coffeecatch \
$(LOCAL_PATH)/../prebuild/$(TARGET_ARCH_ABI)/include \
$(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := libhttrack
LOCAL_LDLIBS := -llog
LOCAL_CFLAGS := -O3 -g -funwind-tables \
-Wl,--no-merge-exidx-entries -Wl,-O1 \
$(HTS_ARMV7_LDFLAGS) -Wl,-O1 \
-W -Wall -Wextra -Werror -Wno-unused-parameter
include $(BUILD_SHARED_LIBRARY)
11 changes: 10 additions & 1 deletion app/src/main/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
APP_ABI := armeabi-v7a
# 64-bit multi-ABI: arm64-v8a is the primary target, armeabi-v7a kept for old
# devices, x86_64 for emulators/CI. 64-bit ABIs require API 21+.
#
# APP_PLATFORM is android-24, not 21: httrack's bundled minizip (ioapi.c) calls
# fseeko/ftello for large-file (>2GB) zip-cache seeks, and bionic only introduces
# them at API 24. Keeping the min at 21 would require an upstream minizip guard
# (fall back to fseek/ftell below 24, capping the cache at 2GB). See the
# android-modernization plan — this is a min-API decision for Xavier.
APP_ABI := arm64-v8a armeabi-v7a x86_64
APP_PLATFORM := android-24
2 changes: 1 addition & 1 deletion app/src/main/jni/httrack
Submodule httrack updated 399 files
Loading
Loading