Skip to content

Commit

Permalink
Add background agent metadata for pixels (#2607)
Browse files Browse the repository at this point in the history
  • Loading branch information
jotaemepereira authored Apr 19, 2024
1 parent 987e6d9 commit ee5067b
Show file tree
Hide file tree
Showing 12 changed files with 333 additions and 8 deletions.
4 changes: 4 additions & 0 deletions DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler
completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) {
ipcScheduler.runQueuedOperations(showWebView: showWebView, completion: completion)
}

func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) {
ipcScheduler.getDebugMetadata(completion: completion)
}
}

#endif
4 changes: 4 additions & 0 deletions DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,8 @@ extension IPCServiceManager: IPCServerInterface {
browserWindowManager.show(domain: domain)
}
}

func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) {
scheduler.getDebugMetadata(completion: completion)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,10 @@ extension InMemoryDataCache: DBPUICommunicationDelegate {
}
}
}

func getBackgroundAgentMetadata() async -> DBPUIDebugMetadata {
let metadata = await scanDelegate?.getBackgroundAgentMetadata()

return mapper.mapToUIDebugMetadata(metadata: metadata, brokerProfileQueryData: brokerProfileQueryData)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ extension DataBrokerProtectionIPCClient: IPCServerInterface {
// If you add a completion block, please remember to call it here too!
})
}

public func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) {
xpc.execute(call: { server in
server.getDebugMetadata(completion: completion)
}, xpcReplyErrorHandler: { error in
os_log("Error \(error.localizedDescription)")
completion(nil)
})
}
}

// MARK: - Incoming communication from the server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import Common
/// A scheduler that works through IPC to request the scheduling to a different process
///
public final class DataBrokerProtectionIPCScheduler: DataBrokerProtectionScheduler {

private let ipcClient: DataBrokerProtectionIPCClient

public init(ipcClient: DataBrokerProtectionIPCClient) {
Expand Down Expand Up @@ -67,4 +66,8 @@ public final class DataBrokerProtectionIPCScheduler: DataBrokerProtectionSchedul
public func runAllOperations(showWebView: Bool) {
ipcClient.runAllOperations(showWebView: showWebView)
}

public func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) {
ipcClient.getDebugMetadata(completion: completion)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,60 @@
import Foundation
import XPCHelper

@objc(DBPBackgroundAgentMetadata)
public final class DBPBackgroundAgentMetadata: NSObject, NSSecureCoding {
enum Consts {
static let backgroundAgentVersionKey = "backgroundAgentVersion"
static let isAgentRunningKey = "isAgentRunning"
static let agentSchedulerStateKey = "agentSchedulerState"
static let lastSchedulerSessionStartTimestampKey = "lastSchedulerSessionStartTimestamp"
}

public static var supportsSecureCoding: Bool = true

let backgroundAgentVersion: String
let isAgentRunning: Bool
let agentSchedulerState: String
let lastSchedulerSessionStartTimestamp: Double?

init(backgroundAgentVersion: String,
isAgentRunning: Bool,
agentSchedulerState: String,
lastSchedulerSessionStartTimestamp: Double?) {
self.backgroundAgentVersion = backgroundAgentVersion
self.isAgentRunning = isAgentRunning
self.agentSchedulerState = agentSchedulerState
self.lastSchedulerSessionStartTimestamp = lastSchedulerSessionStartTimestamp
}

public init?(coder: NSCoder) {
guard let backgroundAgentVersion = coder.decodeObject(of: NSString.self,
forKey: Consts.backgroundAgentVersionKey) as? String,
let agentSchedulerState = coder.decodeObject(of: NSString.self,
forKey: Consts.agentSchedulerStateKey) as? String else {
return nil
}

self.backgroundAgentVersion = backgroundAgentVersion
self.isAgentRunning = coder.decodeBool(forKey: Consts.isAgentRunningKey)
self.agentSchedulerState = agentSchedulerState
self.lastSchedulerSessionStartTimestamp = coder.decodeObject(
of: NSNumber.self,
forKey: Consts.lastSchedulerSessionStartTimestampKey
)?.doubleValue
}

public func encode(with coder: NSCoder) {
coder.encode(self.backgroundAgentVersion as NSString, forKey: Consts.backgroundAgentVersionKey)
coder.encode(self.isAgentRunning, forKey: Consts.isAgentRunningKey)
coder.encode(self.agentSchedulerState as NSString, forKey: Consts.agentSchedulerStateKey)

if let lastSchedulerSessionStartTimestamp = self.lastSchedulerSessionStartTimestamp {
coder.encode(lastSchedulerSessionStartTimestamp as NSNumber, forKey: Consts.lastSchedulerSessionStartTimestampKey)
}
}
}

/// This protocol describes the server-side IPC interface for controlling the tunnel
///
public protocol IPCServerInterface: AnyObject {
Expand Down Expand Up @@ -51,6 +105,9 @@ public protocol IPCServerInterface: AnyObject {
/// Opens a browser window with the specified domain
///
func openBrowser(domain: String)

/// Returns background agent metadata for debugging purposes
func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void)
}

/// This protocol describes the server-side XPC interface.
Expand Down Expand Up @@ -89,6 +146,8 @@ protocol XPCServerInterface {
/// Opens a browser window with the specified domain
///
func openBrowser(domain: String)

func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void)
}

public final class DataBrokerProtectionIPCServer {
Expand Down Expand Up @@ -171,4 +230,8 @@ extension DataBrokerProtectionIPCServer: XPCServerInterface {
func openBrowser(domain: String) {
serverDelegate?.openBrowser(domain: domain)
}

func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) {
serverDelegate?.getDebugMetadata(completion: completion)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,50 @@ struct DBPUIScanHistory: DBPUISendableMessage {
let sitesScanned: Int
}

struct DBPUIDebugMetadata: DBPUISendableMessage {
let lastRunAppVersion: String
let lastRunAgentVersion: String?
let isAgentRunning: Bool
let lastSchedulerOperationType: String? // scan or optOut
let lastSchedulerOperationTimestamp: Double?
let lastSchedulerOperationBrokerUrl: String?
let lastSchedulerErrorMessage: String?
let lastSchedulerErrorTimestamp: Double?
let lastSchedulerSessionStartTimestamp: Double?
let agentSchedulerState: String? // stopped, running or idle
let lastStartedSchedulerOperationType: String?
let lastStartedSchedulerOperationTimestamp: Double?
let lastStartedSchedulerOperationBrokerUrl: String?

init(lastRunAppVersion: String,
lastRunAgentVersion: String? = nil,
isAgentRunning: Bool = false,
lastSchedulerOperationType: String? = nil,
lastSchedulerOperationTimestamp: Double? = nil,
lastSchedulerOperationBrokerUrl: String? = nil,
lastSchedulerErrorMessage: String? = nil,
lastSchedulerErrorTimestamp: Double? = nil,
lastSchedulerSessionStartTimestamp: Double? = nil,
agentSchedulerState: String? = nil,
lastStartedSchedulerOperationType: String? = nil,
lastStartedSchedulerOperationTimestamp: Double? = nil,
lastStartedSchedulerOperationBrokerUrl: String? = nil) {
self.lastRunAppVersion = lastRunAppVersion
self.lastRunAgentVersion = lastRunAgentVersion
self.isAgentRunning = isAgentRunning
self.lastSchedulerOperationType = lastSchedulerOperationType
self.lastSchedulerOperationTimestamp = lastSchedulerOperationTimestamp
self.lastSchedulerOperationBrokerUrl = lastSchedulerOperationBrokerUrl
self.lastSchedulerErrorMessage = lastSchedulerErrorMessage
self.lastSchedulerErrorTimestamp = lastSchedulerErrorTimestamp
self.lastSchedulerSessionStartTimestamp = lastSchedulerSessionStartTimestamp
self.agentSchedulerState = agentSchedulerState
self.lastStartedSchedulerOperationType = lastStartedSchedulerOperationType
self.lastStartedSchedulerOperationTimestamp = lastStartedSchedulerOperationTimestamp
self.lastStartedSchedulerOperationBrokerUrl = lastStartedSchedulerOperationBrokerUrl
}
}

extension DBPUIInitialScanState {
static var empty: DBPUIInitialScanState {
.init(resultsFound: [DBPUIDataBrokerProfileMatch](),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Common
protocol DBPUIScanOps: AnyObject {
func startScan() -> Bool
func updateCacheWithCurrentScans() async
func getBackgroundAgentMetadata() async -> DBPBackgroundAgentMetadata?
}

final class DBPUIViewModel {
Expand Down Expand Up @@ -86,4 +87,12 @@ extension DBPUIViewModel: DBPUIScanOps {
pixelHandler.fire(.generalError(error: error, functionOccurredIn: "DBPUIViewModel.updateCacheWithCurrentScans"))
}
}

func getBackgroundAgentMetadata() async -> DBPBackgroundAgentMetadata? {
return await withCheckedContinuation { continuation in
scheduler.getDebugMetadata { metadata in
continuation.resume(returning: metadata)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ final class DataBrokerProtectionNoOpScheduler: DataBrokerProtectionScheduler {
func runQueuedOperations(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { }
func scanAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { }
func runAllOperations(showWebView: Bool) { }
func getDebugMetadata(completion: (DBPBackgroundAgentMetadata?) -> Void) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ public protocol DataBrokerProtectionScheduler {
func scanAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?)
func runQueuedOperations(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?)
func runAllOperations(showWebView: Bool)

/// Debug operations

func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void)
}

extension DataBrokerProtectionScheduler {
Expand Down Expand Up @@ -121,6 +125,8 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch

public var statusPublisher: Published<DataBrokerProtectionSchedulerStatus>.Publisher { $status }

private var lastSchedulerSessionStartTimestamp: Date?

private lazy var dataBrokerProcessor: DataBrokerProtectionProcessor = {

let runnerProvider = DataBrokerOperationRunnerProvider(privacyConfigManager: privacyConfigManager,
Expand Down Expand Up @@ -174,6 +180,7 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch
completion(.finished)
return
}
self.lastSchedulerSessionStartTimestamp = Date()
self.status = .running
os_log("Scheduler running...", log: .dataBrokerProtection)
self.dataBrokerProcessor.runQueuedOperations(showWebView: showWebView) { [weak self] errors in
Expand Down Expand Up @@ -289,4 +296,31 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch
completion?(errors)
})
}

public func getDebugMetadata(completion: (DBPBackgroundAgentMetadata?) -> Void) {
if let backgroundAgentVersion = Bundle.main.releaseVersionNumber, let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String {
completion(DBPBackgroundAgentMetadata(backgroundAgentVersion: backgroundAgentVersion + " (build: \(buildNumber))",
isAgentRunning: status == .running,
agentSchedulerState: status.toString,
lastSchedulerSessionStartTimestamp: lastSchedulerSessionStartTimestamp?.timeIntervalSince1970))
} else {
completion(DBPBackgroundAgentMetadata(backgroundAgentVersion: "ERROR: Error fetching background agent version",
isAgentRunning: status == .running,
agentSchedulerState: status.toString,
lastSchedulerSessionStartTimestamp: lastSchedulerSessionStartTimestamp?.timeIntervalSince1970))
}
}
}

extension DataBrokerProtectionSchedulerStatus {
var toString: String {
switch self {
case .idle:
return "idle"
case .running:
return "running"
case .stopped:
return "stopped"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ protocol DBPUICommunicationDelegate: AnyObject {
func getInitialScanState() async -> DBPUIInitialScanState
func getMaintananceScanState() async -> DBPUIScanAndOptOutMaintenanceState
func getDataBrokers() async -> [DBPUIDataBroker]
func getBackgroundAgentMetadata() async -> DBPUIDebugMetadata
}

enum DBPUIReceivedMethodName: String {
Expand All @@ -55,6 +56,7 @@ enum DBPUIReceivedMethodName: String {
case initialScanStatus
case maintenanceScanStatus
case getDataBrokers
case getBackgroundAgentMetadata
}

enum DBPUISendableMethodName: String {
Expand All @@ -71,7 +73,7 @@ struct DBPUICommunicationLayer: Subfeature {
weak var delegate: DBPUICommunicationDelegate?

private enum Constants {
static let version = 2
static let version = 3
}

internal init(webURLSettings: DataBrokerProtectionWebUIURLSettingsRepresentable) {
Expand Down Expand Up @@ -104,6 +106,7 @@ struct DBPUICommunicationLayer: Subfeature {
case .initialScanStatus: return initialScanStatus
case .maintenanceScanStatus: return maintenanceScanStatus
case .getDataBrokers: return getDataBrokers
case .getBackgroundAgentMetadata: return getBackgroundAgentMetadata
}

}
Expand Down Expand Up @@ -281,6 +284,10 @@ struct DBPUICommunicationLayer: Subfeature {
return DBPUIDataBrokerList(dataBrokers: dataBrokers)
}

func getBackgroundAgentMetadata(params: Any, origin: WKScriptMessage) async throws -> Encodable? {
return await delegate?.getBackgroundAgentMetadata()
}

func sendMessageToUI(method: DBPUISendableMethodName, params: DBPUISendableMessage, into webView: WKWebView) {
broker?.push(method: method.rawValue, params: params, for: self, into: webView)
}
Expand Down
Loading

0 comments on commit ee5067b

Please sign in to comment.