Skip to content

Android: LLMPipeline close/recreate can SIGSEGV in the same process #1

@allnes

Description

@allnes

Summary

On Android, releasing an LLMPipeline and then creating a new pipeline in the same app process can crash the process with native SIGSEGV during the next warm-up/create cycle.

This was reproduced from the openvino-notes Android integration that uses genai-java-api as the OpenVINO GenAI Java wrapper.

Environment

  • Device: Samsung SM-S931B (pa1q)
  • Android: 16, API 36
  • App package: com.itlab.notes
  • Backend: OpenVINO GenAI Java API + Android CPU pipeline
  • Model assets are already cached in app storage; the repro does not depend on recopying model assets.

Reproduction observed in openvino-notes

  1. Start the app and let the LLM warm-up create the pipeline.
  2. Release AI resources in the live Android process. In Notes this calls through ReleaseNoteAiUseCase -> NoteAiService.release() -> OpenVinoGenAiBackend.close() -> LLMPipeline.close().
  3. Return to the app / trigger warm-up again so a new LLMPipeline is created in the same process.
  4. The second create/warm-up path reaches pipelineReady, then the process dies with native signal 11.

A concrete synthetic trigger used during debugging:

adb shell input keyevent HOME
adb shell am send-trim-memory com.itlab.notes BACKGROUND
adb shell am start -W -n com.itlab.notes/.MainActivity

Actual result

The process exits with native signal 11 after close/recreate:

ApplicationExitInfo:
  process=com.itlab.notes
  reason=2 (SIGNALED)
  status=11
  importance=100
  rss=2.7GB

Relevant app logs from the recreate attempt:

OpenVinoGenAiBackend: createPipeline modelDirReady elapsedMs=4
OpenVinoGenAiBackend: createPipeline runtimeReady elapsedMs=3
OpenVinoGenAiBackend: createPipeline javaApiReady elapsedMs=0
OpenVinoGenAiBackend: createPipeline pipelineReady elapsedMs=18156 ... totalMs=18163
OpenVinoGenAiBackend: warmUp elapsedMs=18163
ActivityManager: Process com.itlab.notes (...) has died: fg TOP

Before the recreate, LLMPipeline.close() did free memory substantially, so disposal itself is doing real native teardown:

Before release: TOTAL PSS about 2.7GB, TOTAL RSS about 2.8GB
After release:  TOTAL PSS about 158MB, TOTAL RSS about 284MB

Expected result

One of these should be true:

  • LLMPipeline.close() safely disposes native resources and a later new LLMPipeline(...) works in the same Android process.
  • Or the API explicitly documents that Android LLMPipeline is process-lifetime only and must not be closed/recreated, and the Java wrapper prevents unsafe reuse patterns where possible.

Current workaround in openvino-notes

openvino-notes temporarily avoids calling LLMPipeline.close() from normal app lifecycle/memory-trim paths. The pipeline is prepared once per live app process and kept alive to avoid the crash. This keeps the app stable, but leaves high native memory resident while the process is alive.

Suspected area

Likely candidates:

  • LLMPipeline.close() / NativeResource lifecycle in Java wrapper.
  • JNI disposal path around PipelineHandle / ov::genai::LLMPipeline destruction.
  • OpenVINO GenAI Android runtime state that is not fully reusable after pipeline teardown.

A smaller dedicated Android smoke test should probably cover:

initialize runtime
create LLMPipeline
optionally generate a short response
close LLMPipeline
create LLMPipeline again in the same process
optionally generate a short response again

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions