Skip to content

Commit 813d02b

Browse files
authored
Restore SessionLifecycleService as no-op (#7318)
In context of class not found exception: #7296 This PR restore a previously deleted service as no operational The user reported a crash after upgrading to BoM 34.1.0 only for some Samsung and Oppo devices in Android 14/15. https://firebase.google.com/support/release-notes/android There was a major refactor on the way of monitoring application lifecycle events and determining when/if a new session should be generated. Which was the main purpose for `SessionLifecycleService`. [Firebase Session](https://github.com/firebase/firebase-android-sdk/blob/main/firebase-sessions/README.md) is used by Crashlytics and Performance internally to measure sessions [The refactor](https://github.com/firebase/firebase-android-sdk/pull/7039/files#diff-ea2eb8012abccd4cb5dccba37ec109f0eaa2a82fe6be852b5be7c32ed8de2b45) proposes the elimination of the service `SessionLifecycleService` in favor of `SharedSessionRepository`. This refactor was released on version `releases/m167` ([see commit here](c9a4a3d)). See diff of m167 with m166 [here](releases/m166...releases/m167). Looking for `SessionLifecycleService` usages into the SDK I found just a leftover reference in an Android Test Manifest. So I can conclude this is not production code. Reviewing the original `SessionLifecycleService` class I found out this service contains a `Binder` implementation It sounds like the Android system on those specific devices (Samsung/Oppo on Android 14/15) might be trying to recreate the `SessionLifecycleService` based on a cached manifest from the previous version of the host app, even though the service class itself is no longer present in the new version. This leads to the `ClassNotFoundException`. **Conclusions:** A) Stale Service Connections (I see this as the root cause, I’d like to review g3 code to confirm there is not source code having references to the removed service): If any component within the host app (or the SDK itself) was bound to `SessionLifecycleService` and the `ServiceConnection` wasn't properly released or unbound before the app update (or if the system is trying to restore a previous binding state), the system will attempt to call `onBind` on the service. When it tries to instantiate `SessionLifecycleService` to do this and finds the class missing, it results in the `ClassNotFoundException`. The git diff showed `android:exported="false"` for the service, which is good as it means only the SDK could bind to it. Why this still leads to `ClassNotFoundException` on update: Even if the new code doesn't try to bind to the removed service anymore, the Android system might still attempt to re-establish connections that it considers active or pending from the previous app session, especially if the app process didn't terminate cleanly or if the system is trying to restore the app's state after an update. If a `ServiceConnection` was active when the app was last running the old version, the system might try to call `onServiceConnected` for that connection, which requires instantiating the service. tl; dr: B) Android /System Caching/State Retention: The Android Package Manager or Activity Manager on certain devices/OS versions might retain information about previously registered services. If the service was started in a "sticky" way, the system will try to restart it after it's killed or after an app update if it believes the service should still be running. When it tries to do so with the updated app that lacks the service class, it crashes. C) Stale System State: Sometimes, especially with certain OEM customizations or newer Android versions, the system's package manager or activity manager might not perfectly clear all references to components from an old app version immediately upon an update. For users experiencing this: The most reliable fix is often a clean reinstall. D) OEM Customizations: Samsung and Oppo devices have their own modifications to Android, which can sometimes lead to different behaviors in how app updates and service lifecycles are handled. **Proposed workaround:** Future Service Removals (Refined Mitigation Strategy for Bound Services): **Version N+1** (Graceful Shutdown & Deprecation): Return the service class in the codebase, modify its onBind(Intent intent) method to return null immediately. This signals to any clients attempting to bind that the service is not available or is shutting down. Crucially, mark the service as `android:enabled="false"` in the AndroidManifest.xml. **This explicitly tells the system the service should not be started or bound**. **Version N+2** (Full Removal): Now that clients have had a version where the service gracefully refuses bindings and is disabled, it's safer to remove the service class and its manifest entry.
1 parent 5be1c09 commit 813d02b

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

firebase-sessions/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22

33
- [fixed] Fixed a bug when the app foregrounds before Sessions has initialized (#7519)
4+
- [changed] Restore SessionLifecycleService as no-op
45

56
# 3.0.3
67

firebase-sessions/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<!--<uses-sdk android:minSdkVersion="21"/>-->
1818

1919
<application>
20+
<service
21+
android:name="com.google.firebase.sessions.SessionLifecycleService"
22+
android:enabled="false"
23+
android:exported="false" />
2024
<service
2125
android:exported="false"
2226
android:name="com.google.firebase.components.ComponentDiscoveryService">
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.sessions
18+
19+
import android.app.Service
20+
import android.content.Intent
21+
22+
/**
23+
* A no-op implementation of SessionLifecycleService.
24+
*
25+
* This service was previously used for session management but has been effectively made a no-op as
26+
* part of the architectural changes introduced in
27+
* [PR #7318](https://github.com/firebase/firebase-android-sdk/pull/7318). It is retained to prevent
28+
* `ClassNotFoundException` for older clients that might still have this service declared in their
29+
* AndroidManifest.xml or for systems attempting to restart a previously running instance of this
30+
* service.
31+
*/
32+
internal class SessionLifecycleService : Service() {
33+
34+
override fun onBind(unused: Intent?) = null
35+
}

0 commit comments

Comments
 (0)