Skip to content

Commit

Permalink
Add double background pixel with timestamps of possible interfering e…
Browse files Browse the repository at this point in the history
…vents (#3749)

Task/Issue URL: https://app.asana.com/0/0/1208997399449398/f

**Description**:
Add double background pixel with timestamps of possibly interfering
events
  • Loading branch information
jaceklyp authored Dec 20, 2024
1 parent 26699be commit c4ac58d
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 14 deletions.
10 changes: 10 additions & 0 deletions Core/Pixel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,16 @@ public struct PixelParameters {

public static let appState = "state"
public static let appEvent = "event"

public static let firstBackgroundTimestamp = "firstBackgroundTimestamp"
public static let secondBackgroundTimestamp = "secondBackgroundTimestamp"
public static let didReceiveMemoryWarningTimestamp = "didReceiveMemoryWarningTimestamp"
public static let didReceiveMXPayloadTimestamp = "didReceiveMXPayloadTimestamp"
public static let didReceiveUNNotification = "didReceiveUNNotification"
public static let didStartRemoteMessagingClientBackgroundTask = "didStartRemoteMessagingClientBackgroundTask"
public static let didStartAppConfigurationFetchBackgroundTask = "didStartAppConfigurationFetchBackgroundTask"
public static let didPerformFetchTimestamp = "didPerformFetchTimestamp"
public static let numberOfBackgrounds = "numberOfBackgrounds"
}

public struct PixelValues {
Expand Down
2 changes: 2 additions & 0 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ extension Pixel {

// MARK: Lifecycle
case appDidTransitionToUnexpectedState
case appDidConsecutivelyBackground
}

}
Expand Down Expand Up @@ -1891,6 +1892,7 @@ extension Pixel.Event {

// MARK: Lifecycle
case .appDidTransitionToUnexpectedState: return "m_debug_app-did-transition-to-unexpected-state"
case .appDidConsecutivelyBackground: return "m_debug_app-did-consecutively-background"

}
}
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/AppConfigurationFetch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class AppConfigurationFetch {
return Date().timeIntervalSince(Self.lastConfigurationRefreshDate) > Constants.minimumConfigurationRefreshInterval
}

static var didStartBackgroundTaskTimestamp: Date?

enum BackgroundRefreshCompletionStatus {

case expired
Expand Down Expand Up @@ -132,6 +134,7 @@ class AppConfigurationFetch {

static func registerBackgroundRefreshTaskHandler() {
BGTaskScheduler.shared.register(forTaskWithIdentifier: Constants.backgroundProcessingTaskIdentifier, using: nil) { (task) in
didStartBackgroundTaskTimestamp = Date()
guard shouldRefresh else {
task.setTaskCompleted(success: true)
scheduleBackgroundRefreshTask()
Expand Down
25 changes: 21 additions & 4 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ import os.log
Configuration.setURLProvider(AppConfigurationURLProvider())
}

crashCollection.startAttachingCrashLogMessages { pixelParameters, payloads, sendReport in
crashCollection.startAttachingCrashLogMessages { [weak self] pixelParameters, payloads, sendReport in
self?.didReceiveMXPayloadTimestamp = Date()
pixelParameters.forEach { params in
Pixel.fire(pixel: .dbCrashDetected, withAdditionalParameters: params, includedParameters: [])

Expand All @@ -198,11 +199,11 @@ import os.log

// Async dispatch because rootViewController may otherwise be nil here
DispatchQueue.main.async {
guard let viewController = self.window?.rootViewController else { return }
guard let viewController = self?.window?.rootViewController else { return }

let crashReportUploaderOnboarding = CrashCollectionOnboarding(appSettings: AppDependencyProvider.shared.appSettings)
crashReportUploaderOnboarding.presentOnboardingIfNeeded(for: payloads, from: viewController, sendReport: sendReport)
self.crashReportUploaderOnboarding = crashReportUploaderOnboarding
self?.crashReportUploaderOnboarding = crashReportUploaderOnboarding
}
}

Expand Down Expand Up @@ -919,7 +920,7 @@ import os.log
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

Logger.lifecycle.debug(#function)

didPerformFetchTimestamp = Date()
AppConfigurationFetch().start(isBackgroundFetch: true) { result in
switch result {
case .noData:
Expand Down Expand Up @@ -1166,6 +1167,21 @@ import os.log
UIApplication.shared.shortcutItems = nil
}
}

var didReceiveMemoryWarningTimestamp: Date?
func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
didReceiveMemoryWarningTimestamp = Date()
}
var didReceiveMXPayloadTimestamp: Date?
var didReceiveUNNotificationTimestamp: Date?
var didStartRemoteMessagingClientBackgroundTaskTimestamp: Date? {
remoteMessagingClient.didStartBackgroundTaskTimestamp
}
var didStartAppConfigurationFetchBackgroundTaskTimestamp: Date? {
AppConfigurationFetch.didStartBackgroundTaskTimestamp
}

var didPerformFetchTimestamp: Date?
}

extension AppDelegate: BlankSnapshotViewRecoveringDelegate {
Expand Down Expand Up @@ -1218,6 +1234,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
didReceiveUNNotificationTimestamp = Date()
if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
let identifier = response.notification.request.identifier

Expand Down
12 changes: 4 additions & 8 deletions DuckDuckGo/AppLifecycle/AppStateTransitions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ extension Background {
case .openURL:
return self
case .backgrounding:
return DoubleBackground()
return DoubleBackground(previousDidEnterBackgroundTimestamp: timestamp, counter: 0)
case .launching, .suspending:
return handleUnexpectedEvent(event)
}
Expand All @@ -102,15 +102,14 @@ extension Background {
extension DoubleBackground {

func apply(event: AppEvent) -> any AppState {
// report event so we know what events can be called at this moment, but do not let SM be stuck in this state just not to be flooded with these events
_ = handleUnexpectedEvent(event)

switch event {
case .activating(let application):
return Active(application: application)
case .suspending(let application):
return Inactive(application: application)
case .launching, .backgrounding, .openURL:
case .backgrounding(let application):
return DoubleBackground(previousDidEnterBackgroundTimestamp: currentDidEnterBackgroundTimestamp, counter: counter)
case .launching, .openURL:
return self
}

Expand All @@ -121,9 +120,6 @@ extension DoubleBackground {
extension InactiveBackground {

func apply(event: AppEvent) -> any AppState {
// report event so we know what events can be called at this moment, but do not let SM be stuck in this state just not to be flooded with these events
_ = handleUnexpectedEvent(event)

switch event {
case .activating(let application):
return Active(application: application)
Expand Down
60 changes: 59 additions & 1 deletion DuckDuckGo/AppLifecycle/AppStates/Background.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,73 @@
//

import UIKit
import Core

struct Background: AppState {

let timestamp = Date()

init(application: UIApplication) {

}

}

struct DoubleBackground: AppState {


private let dateFormatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime]
return formatter
}()

let currentDidEnterBackgroundTimestamp: Date
var counter: Int

init(previousDidEnterBackgroundTimestamp: Date, counter: Int) {
self.currentDidEnterBackgroundTimestamp = Date()
self.counter = counter + 1

var parameters = [
PixelParameters.firstBackgroundTimestamp: dateFormatter.string(from: previousDidEnterBackgroundTimestamp),
PixelParameters.secondBackgroundTimestamp: dateFormatter.string(from: currentDidEnterBackgroundTimestamp)
]

if counter < 5 {
parameters[PixelParameters.numberOfBackgrounds] = String(counter)
}

func isValid(timestamp: Date) -> Bool {
timestamp >= previousDidEnterBackgroundTimestamp && timestamp <= currentDidEnterBackgroundTimestamp
}

if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
if let didReceiveMemoryWarningTimestamp = appDelegate.didReceiveMemoryWarningTimestamp,
isValid(timestamp: didReceiveMemoryWarningTimestamp) {
parameters[PixelParameters.didReceiveMemoryWarningTimestamp] = dateFormatter.string(from: didReceiveMemoryWarningTimestamp)
}
if let didReceiveMXPayloadTimestamp = appDelegate.didReceiveMXPayloadTimestamp,
isValid(timestamp: didReceiveMXPayloadTimestamp) {
parameters[PixelParameters.didReceiveMXPayloadTimestamp] = dateFormatter.string(from: didReceiveMXPayloadTimestamp)
}
if let didReceiveUNNotificationTimestamp = appDelegate.didReceiveUNNotificationTimestamp,
isValid(timestamp: didReceiveUNNotificationTimestamp) {
parameters[PixelParameters.didReceiveUNNotification] = dateFormatter.string(from: didReceiveUNNotificationTimestamp)
}
if let didStartRemoteMessagingClientBackgroundTaskTimestamp = appDelegate.didStartRemoteMessagingClientBackgroundTaskTimestamp,
isValid(timestamp: didStartRemoteMessagingClientBackgroundTaskTimestamp) {
parameters[PixelParameters.didStartRemoteMessagingClientBackgroundTask] = dateFormatter.string(from: didStartRemoteMessagingClientBackgroundTaskTimestamp)
}
if let didStartAppConfigurationFetchBackgroundTaskTimestamp = appDelegate.didStartAppConfigurationFetchBackgroundTaskTimestamp,
isValid(timestamp: didStartAppConfigurationFetchBackgroundTaskTimestamp) {
parameters[PixelParameters.didStartAppConfigurationFetchBackgroundTask] = dateFormatter.string(from: didStartAppConfigurationFetchBackgroundTaskTimestamp)
}
if let didPerformFetchTimestamp = appDelegate.didPerformFetchTimestamp,
isValid(timestamp: didPerformFetchTimestamp) {
parameters[PixelParameters.didPerformFetchTimestamp] = dateFormatter.string(from: didPerformFetchTimestamp)
}
}
Pixel.fire(pixel: .appDidConsecutivelyBackground, withAdditionalParameters: parameters)
}

}
5 changes: 4 additions & 1 deletion DuckDuckGo/RemoteMessagingClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ final class RemoteMessagingClient: RemoteMessagingProcessing {
let store: RemoteMessagingStoring
let remoteMessagingAvailabilityProvider: RemoteMessagingAvailabilityProviding

var didStartBackgroundTaskTimestamp: Date?

convenience init(
bookmarksDatabase: CoreDataDatabase,
appSettings: AppSettings,
Expand Down Expand Up @@ -113,7 +115,8 @@ extension RemoteMessagingClient {
let remoteMessagingAvailabilityProvider = remoteMessagingAvailabilityProvider
let store = store

BGTaskScheduler.shared.register(forTaskWithIdentifier: Constants.backgroundRefreshTaskIdentifier, using: nil) { task in
BGTaskScheduler.shared.register(forTaskWithIdentifier: Constants.backgroundRefreshTaskIdentifier, using: nil) { [weak self] task in
self?.didStartBackgroundTaskTimestamp = Date()
guard Self.shouldRefresh else {
task.setTaskCompleted(success: true)
Self.scheduleBackgroundRefreshTask()
Expand Down

0 comments on commit c4ac58d

Please sign in to comment.