Skip to content

feat: [SDK-5538] remote kill switch with a placeholder OneSignalImpV2 - #2801

Draft
abdulraqeeb33 wants to merge 1 commit into
never-crash/1-sdk-operationfrom
never-crash/2-kill-switch
Draft

abdulraqeeb33 wants to merge 1 commit into
never-crash/1-sdk-operationfrom
never-crash/2-kill-switch

Conversation

@abdulraqeeb33

@abdulraqeeb33 abdulraqeeb33 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Stack (base feat/never-crash, merged to main as one unit; split out of #2793):

  1. refactor: [SDK-5538] add SdkOperation names for init-gated entry points #2800 SdkOperation names
  2. feat: [SDK-5538] remote kill switch with a placeholder OneSignalImpV2 #2801 Kill switch with a placeholder OneSignalImpV2 (this PR)
  3. feat: [SDK-5538] deferred managers that stand in before init #2802 Deferred managers
  4. fix: [SDK-5538] never crash on invalid init or calls before init #2803 Never-crash init

Description

One Line Summary

A remote kill switch that picks the IOneSignal implementation at process start, with OneSignalImpV2 as a placeholder copy of OneSignalImp.

Details

Motivation

Part of SDK-5538. The never-crash init (PR 4) rewrites init, so it ships behind a flag that can bring back the old implementation without a release.

Scope

  • NeverCrashKillSwitch reads the feature flags cached by the previous run from ActivityLifecycleInitializer (androidx.startup, before Application.onCreate), once per process. A backend change applies on the next cold start.
  • sdk_never_crash_disabled in the cached sdkRemoteFeatureFlags (any casing) selects OneSignalImp; otherwise OneSignalImpV2.
  • Present means off: installs whose init never succeeds never fetch flags, so they keep the new behavior. A fresh install, a locked device, an unreadable cache, or first use before evaluation also keep OneSignalImpV2.
  • OneSignal creates its implementation through the switch.
  • OneSignalImpV2 is a verbatim copy of OneSignalImp (only the class name differs), so behavior is unchanged either way. PR 4's diff on it then reads as the change from the old code.
  • localOverride in NeverCrashKillSwitch forces either implementation for local testing.
  • The flag still needs to be created on the backend.

Known gaps (follow-ups)

  • The switch reads the OneSignal prefs file on the main thread before Application.onCreate.
  • The startup provider only runs in the main process, so secondary processes always get OneSignalImpV2.

Testing

Unit testing

NeverCrashKillSwitchTests: the flag selects OneSignalImp in any casing; no flag, a fresh install, an unreadable cache, a locked device and first use before evaluation select OneSignalImpV2. All suites, spotless, detekt and apiCheck pass.

Manual testing

Not yet tested on a device.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

NeverCrashKillSwitch reads the feature flags cached by the previous run
at process start (ActivityLifecycleInitializer) and picks the IOneSignal
implementation once per process: sdk_never_crash_disabled present means
OneSignalImp, otherwise OneSignalImpV2. A fresh install, a locked device,
an unreadable cache, or first use before evaluation keep OneSignalImpV2.

OneSignalImpV2 is a verbatim copy of OneSignalImp for now, so behavior is
unchanged either way. The never-crash init lands on it later in this stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

📊 Diff Coverage Report

Diff Coverage Report (Changed Lines Only)

Gate: aggregate coverage on changed executable lines must be ≥ 80% (JaCoCo line data for lines touched in the diff).

Changed Files Coverage

  • OneSignal.kt: 1/1 touched executable lines (100.0%) (3 touched lines in diff)
  • ActivityLifecycleInitializer.kt: 1/1 touched executable lines (100.0%) (4 touched lines in diff)
  • NeverCrashKillSwitch.kt: 29/29 touched executable lines (100.0%) (76 touched lines in diff)
  • OneSignalImpV2.kt: 108/399 touched executable lines (27.1%) (919 touched lines in diff)
    • 291 uncovered touched lines in this file

Overall (aggregate gate)

139/430 touched executable lines covered (32.3% — requires ≥ 80%)

Per-file detail (informational; gate is aggregate above):

  • OneSignalImpV2.kt: 27.1% (291 uncovered touched lines)

❌ Coverage Check Failed

Aggregate coverage on touched lines is 32.3% (minimum 80%).

📥 View workflow run

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.

1 participant