Document JNI host checks and their platform requirements
This commit is contained in:
1 parent
0931eeedad
commit
269d09815b
2 files changed
+38
-3
No files matched your search
@@ -0,0 +1,34 @@
|
||||
# Проверка JNI-доставки логов
|
||||
|
||||
Linux host, без телефона и запущенного ядра. Нужны Python 3, C99-компилятор,
|
||||
заголовки OpenSSL и JDK с `include/jni.h`. Используется настоящий
|
||||
`jni_bridge/android_jni_bridge.c`: неиспользуемые функции отсекает ELF linker.
|
||||
JNI function tables моделируют JVM, локальные ссылки и принудительные отказы;
|
||||
Android logcat заменён только проверяющим приёмником диагностики.
|
||||
|
||||
Из корня репозитория:
|
||||
|
||||
```sh
|
||||
python3 tools/chatgui-android/tests/jni_log/run.py
|
||||
# Явный JDK / другой компилятор:
|
||||
CC=clang python3 tools/chatgui-android/tests/jni_log/run.py --java-home /path/to/jdk
|
||||
```
|
||||
|
||||
В Android Gradle на Linux задача `:app:testJniLog` запускается перед JVM-тестами
|
||||
приложения, включая `:app:testDebugUnitTest`. На других ОС эта host-задача пропускается.
|
||||
Android `AttachCurrentThread` принимает `JNIEnv**`, JDK — `void**` с тем же ABI;
|
||||
только это различие типов допускается host-компилятором. Настоящая NDK-сборка
|
||||
проверяет Android-заголовки отдельно. Host-модели не включаются в APK.
|
||||
|
||||
22 сценария проверяют GetEnv/attach/detach, получение callback/class/method,
|
||||
создание/копирование массивов, исходный UTF-8 с кириллицей/emoji, освобождение
|
||||
всех локальных ссылок и продолжение после ошибки. Отдельно проверяются
|
||||
Java-исключение callback, сохранение чужого pending exception, подавление
|
||||
рекурсии и удержание local ref при замене global callback.
|
||||
Для операций, допускающих `NULL` без Java-исключения, проверяются оба отказа.
|
||||
|
||||
Тест не запускает ART и не проверяет сборщик мусора Android; JVM-тест
|
||||
`NativeLogContractTest` дополнительно сопоставляет C lookup с дескриптором
|
||||
скомпилированного Kotlin `onNativeLog(Int, ByteArray?, ByteArray?)`.
|
||||
Правила JNI: [Android JNI tips](https://developer.android.com/ndk/guides/jni-tips),
|
||||
[JNI function specification](https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html).
|
||||
@@ -3,6 +3,7 @@
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
@@ -18,19 +19,19 @@ def main():
|
||||
java_home = args.java_home or (Path(javac).resolve().parents[1] if javac else None)
|
||||
if java_home is None or not (java_home / "include/jni.h").is_file():
|
||||
parser.error("JDK JNI headers missing; pass --java-home")
|
||||
compiler = os.environ.get("CC", "cc")
|
||||
compiler = shlex.split(os.environ.get("CC", "cc"))
|
||||
includes = [directory, java_home / "include", java_home / "include/linux",
|
||||
root / "src", root / "src/transport_layer", root / "src/routing_layer",
|
||||
root / "src/chat", root / "src/media_async", root / "lib"]
|
||||
with tempfile.TemporaryDirectory(prefix="utun-jni-log-") as output:
|
||||
binary = Path(output) / "test_jni_log"
|
||||
command = [compiler, "-std=c99", "-D_DEFAULT_SOURCE", "-D__ANDROID__", "-DUSE_OPENSSL",
|
||||
command = compiler + ["-std=c99", "-D_DEFAULT_SOURCE", "-D__ANDROID__", "-DUSE_OPENSSL",
|
||||
"-ffunction-sections", "-fdata-sections", "-Wl,--gc-sections", "-pthread",
|
||||
# Android JNI принимает JNIEnv**, JDK — void**; ABI одинаков, чужие callbacks здесь не вызываются.
|
||||
"-Wno-incompatible-pointer-types"]
|
||||
command += [f"-I{path}" for path in includes]
|
||||
command += [str(directory / "test_jni_log.c"), "-o", str(binary)]
|
||||
subprocess.run(command, check=True)
|
||||
subprocess.run(command, check=True, timeout=90)
|
||||
subprocess.run([str(binary)], check=True, timeout=15)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user