Skip to content

Commit

Permalink
Injectable monitors (kstenerud#496)
Browse files Browse the repository at this point in the history
* Basic implementation of injection and new property system

* Basic implementation of the new system for CPP monitor

* Implement for Deadlock monitor

* Implement for Mach monitor

* Implement for Memory monitor

* Implement for NSException

* Add missing property to Mach monitor

* Implement for Signal monitor

* Implement for System monitor

* Implement for User monitor

* Implement for Zombie

* Add name to AppState

* Create helper for MonitorAPI with inline functions

* Use new helper

* Update C facade with the new injection mechanism

* Create DiscSpace monitor

* Add boot time monitor

* return `kscm_setEventCallback` back

* Fix monitors logic

* Add privacy manifest for Disc Space

* Add privacy manifest for Boot Time

* Update Podspec with the new modules

* Fix declaration of functions in KSCrashMonitor

* Fix typos

* Fix podspec linting issues

* Fix forward declaration issue

* Fix imports for new monitors

* Add new schemes

* Fix build for WatchOS

* Remove constant pointer in `name` in Monitor API

* Move MachineContext test to its own Case

* Add KSCrashMonitor tests

* Add some tests and sort

* Make AppState Monitor compilable

* Fix compilation

* Temporary fixed Memory Monitor Tests

* Try to introduce deduplication

* Add KSCrashMonitor_BootTime_Tests

* Add KSCrashMonitor_DiscSpace_Tests

* Return documentation to KSCrashMonitorType

* Remove privacy-related APIs from KSCrash API

* Add some documentation

* Follow the current style in files headers

* Uddate KSCrashReport logic

* rename name to monitorId

* Address small changes to KSCrashMonitor

* Raname monitorId in CrashContext

* Rename monitorFlags in Crash Context

* Address Monitor Context filling

* Deduplicate APIs with monitorId

* Rename to monitorFlags

* Support monitor removing

* Move `safeStrcmp` to `KSString`

* Shorten monitor names

for optimisation

* Add `static` to `ksmc_fillMonitorContext`

* Return NULL if monitor is not supported on platform

* setMonitors prior to install in Tests

* Return optional fields in `systemInfo`

* Address issues from PR
  • Loading branch information
GLinnik21 authored Jun 16, 2024
1 parent b296eca commit 4b2360f
Show file tree
Hide file tree
Showing 41 changed files with 2,083 additions and 607 deletions.
67 changes: 67 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/BootTimeMonitor.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BootTimeMonitor"
BuildableName = "BootTimeMonitor"
BlueprintName = "BootTimeMonitor"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BootTimeMonitor"
BuildableName = "BootTimeMonitor"
BlueprintName = "BootTimeMonitor"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
34 changes: 34 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DiscSpaceMonitor"
BuildableName = "DiscSpaceMonitor"
BlueprintName = "DiscSpaceMonitor"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand Down Expand Up @@ -170,6 +184,26 @@
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "KSCrashBootTimeMonitorTests"
BuildableName = "KSCrashBootTimeMonitorTests"
BlueprintName = "KSCrashBootTimeMonitorTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "KSCrashDiscSpaceMonitorTests"
BuildableName = "KSCrashDiscSpaceMonitorTests"
BlueprintName = "KSCrashDiscSpaceMonitorTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
12 changes: 12 additions & 0 deletions KSCrash.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ Pod::Spec.new do |s|
configure_subspec.call(recording_core)
end

s.subspec 'BootTimeMonitor' do |boot_time_monitor|
boot_time_monitor.dependency 'KSCrash/RecordingCore'

configure_subspec.call(boot_time_monitor)
end

s.subspec 'DiscSpaceMonitor' do |disc_space_monitor|
disc_space_monitor.dependency 'KSCrash/RecordingCore'

configure_subspec.call(disc_space_monitor)
end

s.subspec 'ReportingCore' do |reporting_core|
reporting_core.dependency 'KSCrash/Core'
reporting_core.ios.frameworks = 'SystemConfiguration'
Expand Down
44 changes: 44 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ let package = Package(
name: "Recording",
targets: [Targets.recording]
),
.library(
name: "DiscSpaceMonitor",
targets: [Targets.discSpaceMonitor]
),
.library(
name: "BootTimeMonitor",
targets: [Targets.bootTimeMonitor]
),
],
targets: [
.target(
Expand Down Expand Up @@ -172,6 +180,40 @@ let package = Package(
]
),

.target(
name: Targets.discSpaceMonitor,
dependencies: [
.target(name: Targets.recordingCore)
],
resources: [
.copy("Resources/PrivacyInfo.xcprivacy")
]
),
.testTarget(
name: Targets.discSpaceMonitor.tests,
dependencies: [
.target(name: Targets.discSpaceMonitor),
.target(name: Targets.recordingCore)
]
),

.target(
name: Targets.bootTimeMonitor,
dependencies: [
.target(name: Targets.recordingCore)
],
resources: [
.copy("Resources/PrivacyInfo.xcprivacy")
]
),
.testTarget(
name: Targets.bootTimeMonitor.tests,
dependencies: [
.target(name: Targets.bootTimeMonitor),
.target(name: Targets.recordingCore)
]
),

.target(
name: Targets.testTools,
dependencies: [
Expand All @@ -190,6 +232,8 @@ enum Targets {
static let recordingCore = "KSCrashRecordingCore"
static let reportingCore = "KSCrashReportingCore"
static let core = "KSCrashCore"
static let discSpaceMonitor = "KSCrashDiscSpaceMonitor"
static let bootTimeMonitor = "KSCrashBootTimeMonitor"
static let testTools = "KSCrashTestTools"
}

Expand Down
104 changes: 104 additions & 0 deletions Sources/KSCrashBootTimeMonitor/KSCrashMonitor_BootTime.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// KSCrashMonitor_BootTime.c
//
// Created by Gleb Linnik on 04.06.2024.
//
// Copyright (c) 2012 Karl Stenerud. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall remain in place
// in this source code.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#import "KSCrashMonitor_BootTime.h"

#import "KSCrashMonitorContext.h"
#import "KSSysCtl.h"
#import "KSDate.h"

#import <sys/types.h>
#import <Foundation/Foundation.h>

static volatile bool g_isEnabled = false;

__attribute__((unused)) // For tests. Declared as extern in TestCase
void kscm_bootTime_resetState(void)
{
g_isEnabled = false;
}

/** Get a sysctl value as an NSDate.
*
* @param name The sysctl name.
*
* @return The result of the sysctl call.
*/
static const char* dateSysctl(const char* name)
{
struct timeval value = kssysctl_timevalForName(name);
char* buffer = malloc(21);
ksdate_utcStringFromTimestamp(value.tv_sec, buffer);
return buffer;
}

#pragma mark - API -

static const char* monitorId(void)
{
return "BootTime";
}

static void setEnabled(bool isEnabled)
{
if(isEnabled != g_isEnabled)
{
g_isEnabled = isEnabled;
}
}

static bool isEnabled(void)
{
return g_isEnabled;
}

static void addContextualInfoToEvent(KSCrash_MonitorContext* eventContext)
{
if(g_isEnabled)
{
eventContext->System.bootTime = dateSysctl("kern.boottime");
}
}

KSCrashMonitorAPI* kscm_boottime_getAPI(void)
{
static KSCrashMonitorAPI api =
{
.monitorId = monitorId,
.setEnabled = setEnabled,
.isEnabled = isEnabled,
.addContextualInfoToEvent = addContextualInfoToEvent
};
return &api;
}

#pragma mark - Injection -

__attribute__((constructor))
static void kscm_boottime_register(void)
{
kscm_addMonitor(kscm_boottime_getAPI());
}
36 changes: 36 additions & 0 deletions Sources/KSCrashBootTimeMonitor/Resources/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeOtherDiagnosticData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>3D61.1</string>
</array>
</dict>
</array>
</dict>
</plist>
45 changes: 45 additions & 0 deletions Sources/KSCrashBootTimeMonitor/include/KSCrashMonitor_BootTime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// KSCrashMonitor_BootTime.h
//
// Created by Gleb Linnik on 04.06.2024.
//
// Copyright (c) 2012 Karl Stenerud. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall remain in place
// in this source code.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//


#ifndef KSCrashMonitor_BootTime_h
#define KSCrashMonitor_BootTime_h

#include "KSCrashMonitor.h"

#ifdef __cplusplus
extern "C" {
#endif

/** Access the Monitor API.
*/
KSCrashMonitorAPI* kscm_boottime_getAPI(void);

#ifdef __cplusplus
}
#endif

#endif /* KSCrashMonitor_BootTime_h */
Loading

0 comments on commit 4b2360f

Please sign in to comment.