Skip to content

Close the ApplicationExitInfo trace stream in Crashlytics NDK - #8531

Open
jrodiz wants to merge 3 commits into
firebase:mainfrom
jrodiz:hotfix/jrc--8510.Close.ApplicationExitInfo.trace.input.stream
Open

Close the ApplicationExitInfo trace stream in Crashlytics NDK#8531
jrodiz wants to merge 3 commits into
firebase:mainfrom
jrodiz:hotfix/jrc--8510.Close.ApplicationExitInfo.trace.input.stream

Conversation

@jrodiz

@jrodiz jrodiz commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #8510

Problem

CrashpadController.getTraceFileFromApplicationExitInfo() drained the stream returned by ApplicationExitInfo.getTraceInputStream() but never closed it. That stream wraps a ParcelFileDescriptor.AutoCloseInputStream, so close() is the only thing that releases the file descriptor — without it the fd survives until finalization and trips CloseGuard under StrictMode.detectLeakedClosableObjects():

Caused by dalvik.system.CloseGuard$CloseGuardException: Explicit termination method 'close' not called
       at android.app.ApplicationExitInfo.getTraceInputStream(ApplicationExitInfo.java:1000)
       at com.google.firebase.crashlytics.ndk.CrashpadController.getTraceFileFromApplicationExitInfo(CrashpadController.java:264)
       at com.google.firebase.crashlytics.internal.common.CrashlyticsCore.doBackgroundInitialization(CrashlyticsCore.java:250)

Crashlytics runs this during background init to finalize the previous session, so it leaks on every app start following a native crash.

Fix

Close at the acquisition site with try-with-resources, releasing the fd on normal completion, read failure and encode failure alike:

try (InputStream traceInputStream = applicationExitInfo.getTraceInputStream()) {
  return convertInputStreamToString(traceInputStream);
} catch (IOException e) {
  Logger.getLogger().w("Failed to get input stream from ApplicationExitInfo");
}

convertInputStreamToString is left untouched — ownership stays with the caller. Visibility was relaxed to @VisibleForTesting static for coverage. getTraceInputStream() may return null, and try-with-resources null-checks before close() (JLS 14.20.3.1), so that path is unchanged.

Scope

SessionReportingCoordinator's ANR path calls the same API but already closes the stream via a BufferedInputStream in try-with-resources. Those are the only two call sites, so this change stays confined to the NDK module.

Risk

Low. The stream was already read to EOF before being abandoned, so closing it adds no new failure mode; a throwing close() lands in the existing catch (IOException) and degrades to today's "trace unavailable" → null behaviour. The visibility change is source- and binary-safe: the method is not part of any public or @KeepForSdk API surface, and api.txt is unaffected.

jrodiz added 3 commits August 12, 2026 17:54
The stream from getTraceInputStream() wraps a ParcelFileDescriptor that
is only released on close, so leaving it open leaked an fd until
finalization and tripped StrictMode CloseGuard. Fixes firebase#8510.
Covers that the ApplicationExitInfo trace stream is closed on success
and on read failure, plus the null-trace path and the round trip of
convertInputStreamToString.
@gemini-code-assist

Copy link
Copy Markdown
Contributor
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

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.

Crashlytics NDK never closes ApplicationExitInfo.getTraceInputStream(), leaking a ParcelFileDescriptor

1 participant