diff --git a/firebase-perf/CHANGELOG.md b/firebase-perf/CHANGELOG.md index 4fb751df726..0389ef66c42 100644 --- a/firebase-perf/CHANGELOG.md +++ b/firebase-perf/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased -* +* [fixed] Fixed a `NullPointerException` crash when instrumenting screen traces + on Android 7, 8, and 9. + (#4146) # 20.2.0 diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/application/FrameMetricsRecorder.java b/firebase-perf/src/main/java/com/google/firebase/perf/application/FrameMetricsRecorder.java index dc7052b4049..9d63dce21cb 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/application/FrameMetricsRecorder.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/application/FrameMetricsRecorder.java @@ -15,6 +15,7 @@ package com.google.firebase.perf.application; import android.app.Activity; +import android.os.Build; import android.util.SparseIntArray; import androidx.core.app.FrameMetricsAggregator; import androidx.fragment.app.Fragment; @@ -107,11 +108,22 @@ public Optional stop() { } Optional data = this.snapshot(); try { + // No reliable way to check for hardware-acceleration, so we must catch retroactively (#2736). frameMetricsAggregator.remove(activity); - } catch (IllegalArgumentException err) { + } catch (IllegalArgumentException | NullPointerException ex) { + // Both of these exceptions result from android.view.View.addFrameMetricsListener silently + // failing when the view is not hardware-accelerated. Successful addFrameMetricsListener + // stores an observer in a list, and initializes the list if it was uninitialized. Invoking + // View.removeFrameMetricsListener(listener) throws IAE if it doesn't exist in the list, or + // throws NPE if the list itself was never initialized (#4184). + if (ex instanceof NullPointerException && Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + // Re-throw above API 28, since the NPE is fixed in API 29: + // https://android.googlesource.com/platform/frameworks/base/+/140ff5ea8e2d99edc3fbe63a43239e459334c76b + throw ex; + } logger.warn( - "View not hardware accelerated. Unable to collect FrameMetrics. %s", err.toString()); - return Optional.absent(); + "View not hardware accelerated. Unable to collect FrameMetrics. %s", ex.toString()); + data = Optional.absent(); } frameMetricsAggregator.reset(); isRecording = false;