mirror of
https://github.com/google/santa.git
synced 2026-01-15 01:08:12 -05:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4b1fbb9e6 | ||
|
|
209eaff3c6 | ||
|
|
c3f70703fd | ||
|
|
f2967e7b94 | ||
|
|
77c46b5c43 | ||
|
|
5fda5bc081 | ||
|
|
33a7b38c6a | ||
|
|
2a7c0bd58c | ||
|
|
86e4d0db0f | ||
|
|
1310fea64d | ||
|
|
382f5a5bb9 | ||
|
|
ff3303e312 |
@@ -71,7 +71,7 @@
|
||||
#pragma mark Connection handling
|
||||
|
||||
- (void)createConnection {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
|
||||
self.listener = [[SNTXPCConnection alloc] initClientWithName:[SNTXPCNotifierInterface serviceId]
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
// Simple class to hold the data of a mach_header and the offset within the file
|
||||
// in which that header was found.
|
||||
@@ -39,15 +40,14 @@
|
||||
|
||||
@interface SNTFileInfo ()
|
||||
@property NSString *path;
|
||||
@property NSData *fileData;
|
||||
|
||||
// Dictionary of MachHeaderWithOffset objects where the keys are the architecture strings
|
||||
@property NSDictionary *machHeaders;
|
||||
@property NSFileHandle *fileHandle;
|
||||
@property NSUInteger fileSize;
|
||||
|
||||
// Cached properties
|
||||
@property NSBundle *bundleRef;
|
||||
@property NSDictionary *infoDict;
|
||||
@property NSDictionary *quarantineDict;
|
||||
@property NSDictionary *cachedHeaders;
|
||||
@end
|
||||
|
||||
@implementation SNTFileInfo
|
||||
@@ -69,11 +69,13 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
return nil;
|
||||
}
|
||||
|
||||
_fileData = [NSData dataWithContentsOfFile:_path
|
||||
options:NSDataReadingUncached
|
||||
error:error];
|
||||
if (_fileData.length == 0) return nil;
|
||||
[self parseMachHeaders];
|
||||
_fileHandle = [NSFileHandle fileHandleForReadingAtPath:_path];
|
||||
|
||||
struct stat fileStat;
|
||||
fstat(_fileHandle.fileDescriptor, &fileStat);
|
||||
_fileSize = fileStat.st_size;
|
||||
|
||||
if (_fileSize == 0) return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -84,10 +86,31 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
}
|
||||
|
||||
- (NSString *)SHA1 {
|
||||
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1(self.fileData.bytes, (unsigned int)self.fileData.length, sha1);
|
||||
const int chunkSize = 4096;
|
||||
|
||||
CC_SHA1_CTX c;
|
||||
CC_SHA1_Init(&c);
|
||||
for (uint64_t offset = 0; offset < self.fileSize; offset += chunkSize) {
|
||||
@autoreleasepool {
|
||||
int readSize;
|
||||
if (offset + chunkSize > self.fileSize) {
|
||||
readSize = (int)(self.fileSize - offset);
|
||||
} else {
|
||||
readSize = chunkSize;
|
||||
}
|
||||
|
||||
NSData *chunk = [self safeSubdataWithRange:NSMakeRange(offset, readSize)];
|
||||
if (!chunk) {
|
||||
CC_SHA1_Final(NULL, &c);
|
||||
return nil;
|
||||
}
|
||||
|
||||
CC_SHA1_Update(&c, chunk.bytes, readSize);
|
||||
}
|
||||
}
|
||||
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1_Final(sha1, &c);
|
||||
|
||||
// Convert the binary SHA into hex
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)sha1[i]];
|
||||
@@ -97,23 +120,45 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
}
|
||||
|
||||
- (NSString *)SHA256 {
|
||||
const int chunkSize = 4096;
|
||||
|
||||
CC_SHA256_CTX c;
|
||||
CC_SHA256_Init(&c);
|
||||
for (uint64_t offset = 0; offset < self.fileSize; offset += chunkSize) {
|
||||
@autoreleasepool {
|
||||
int readSize;
|
||||
if (offset + chunkSize > self.fileSize) {
|
||||
readSize = (int)(self.fileSize - offset);
|
||||
} else {
|
||||
readSize = chunkSize;
|
||||
}
|
||||
|
||||
NSData *chunk = [self safeSubdataWithRange:NSMakeRange(offset, readSize)];
|
||||
if (!chunk) {
|
||||
CC_SHA256_Final(NULL, &c);
|
||||
return nil;
|
||||
}
|
||||
|
||||
CC_SHA256_Update(&c, chunk.bytes, readSize);
|
||||
}
|
||||
}
|
||||
unsigned char sha256[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256(self.fileData.bytes, (unsigned int)self.fileData.length, sha256);
|
||||
CC_SHA256_Final(sha256, &c);
|
||||
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)sha256[i]];
|
||||
}
|
||||
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
- (NSString *)machoType {
|
||||
if ([self isScript]) return @"Script";
|
||||
if ([self isDylib]) return @"Dynamic Library";
|
||||
if ([self isKext]) return @"Kernel Extension";
|
||||
if ([self isFat]) return @"Fat Binary";
|
||||
if ([self isMachO]) return @"Thin Binary";
|
||||
if ([self isScript]) return @"Script";
|
||||
return @"Unknown (not executable?)";
|
||||
}
|
||||
|
||||
@@ -134,11 +179,11 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
}
|
||||
|
||||
- (BOOL)isMachO {
|
||||
return ([self.machHeaders count] > 0);
|
||||
return (self.machHeaders.count > 0);
|
||||
}
|
||||
|
||||
- (BOOL)isFat {
|
||||
return ([self.machHeaders count] > 1);
|
||||
return (self.machHeaders.count > 1);
|
||||
}
|
||||
|
||||
- (BOOL)isScript {
|
||||
@@ -148,15 +193,14 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
|
||||
- (BOOL)isExecutable {
|
||||
struct mach_header *mach_header = [self firstMachHeader];
|
||||
if (!mach_header) return NO;
|
||||
if (mach_header->filetype == MH_OBJECT || mach_header->filetype == MH_EXECUTE) return YES;
|
||||
if (mach_header && mach_header->filetype == MH_EXECUTE) return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isMissingPageZero {
|
||||
// This method only checks i386 arch because the kernel enforces this for other archs
|
||||
// See bsd/kern/mach_loader.c, search for enforce_hard_pagezero.
|
||||
MachHeaderWithOffset *x86Header = self.machHeaders[@"i386"];
|
||||
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86]];
|
||||
if (!x86Header) return NO;
|
||||
|
||||
struct mach_header *mh = (struct mach_header *)[x86Header.data bytes];
|
||||
@@ -259,6 +303,8 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
return [self.infoPlist objectForKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
#pragma mark Quarantine Data
|
||||
|
||||
- (NSString *)quarantineDataURL {
|
||||
NSURL *url = [self quarantineData][(__bridge NSString *)kLSQuarantineDataURLKey];
|
||||
return [url absoluteString];
|
||||
@@ -277,24 +323,21 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
return [self quarantineData][(__bridge NSString *)kLSQuarantineTimeStampKey];
|
||||
}
|
||||
|
||||
- (NSUInteger)fileSize {
|
||||
return self.fileData.length;
|
||||
}
|
||||
|
||||
#pragma mark Internal Methods
|
||||
|
||||
- (void)parseMachHeaders {
|
||||
if (self.machHeaders) return;
|
||||
- (NSDictionary *)machHeaders {
|
||||
if (self.cachedHeaders) return self.cachedHeaders;
|
||||
|
||||
// Sanity check file length
|
||||
if (self.fileData.length < sizeof(struct mach_header)) {
|
||||
self.machHeaders = [NSDictionary dictionary];
|
||||
return;
|
||||
if (self.fileSize < sizeof(struct mach_header)) {
|
||||
self.cachedHeaders = [NSDictionary dictionary];
|
||||
return self.cachedHeaders;
|
||||
}
|
||||
|
||||
NSMutableDictionary *machHeaders = [NSMutableDictionary dictionary];
|
||||
|
||||
NSData *machHeader = [self parseSingleMachHeader:self.fileData];
|
||||
NSData *machHeader = [self parseSingleMachHeader:[self safeSubdataWithRange:NSMakeRange(0,
|
||||
4096)]];
|
||||
if (machHeader) {
|
||||
struct mach_header *mh = (struct mach_header *)[machHeader bytes];
|
||||
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader offset:0];
|
||||
@@ -328,7 +371,8 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
|
||||
self.machHeaders = [machHeaders copy];
|
||||
self.cachedHeaders = [machHeaders copy];
|
||||
return self.cachedHeaders;
|
||||
}
|
||||
|
||||
- (NSData *)parseSingleMachHeader:(NSData *)inputData {
|
||||
@@ -391,7 +435,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
NSData *sectData = [self safeSubdataWithRange:NSMakeRange(offset, sz_section)];
|
||||
if (!sectData) return nil;
|
||||
struct section_64 *sect = (struct section_64 *)[sectData bytes];
|
||||
if (strncmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
|
||||
if (sect && strncmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
|
||||
NSData *plistData = [self safeSubdataWithRange:NSMakeRange(sect->offset, sect->size)];
|
||||
if (!plistData) return nil;
|
||||
NSDictionary *plist;
|
||||
@@ -407,20 +451,23 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
}
|
||||
|
||||
///
|
||||
/// Return one of the mach_header's in this file.
|
||||
/// Return the first mach_header in this file.
|
||||
///
|
||||
- (struct mach_header *)firstMachHeader {
|
||||
return (struct mach_header *)([[[[self.machHeaders allValues] firstObject] data] bytes]);
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// Wrap @c subdataWithRange: in a @@try/@@catch, returning nil on exception.
|
||||
/// Useful for when the range is beyond the end of the file.
|
||||
/// Extract a range of the file as an NSData, handling any exceptions.
|
||||
/// Returns nil if the requested range is outside of the range of the file.
|
||||
///
|
||||
- (NSData *)safeSubdataWithRange:(NSRange)range {
|
||||
@try {
|
||||
return [self.fileData subdataWithRange:range];
|
||||
if ((range.location + range.length) > self.fileSize) return nil;
|
||||
[self.fileHandle seekToFileOffset:range.location];
|
||||
NSData *d = [self.fileHandle readDataOfLength:range.length];
|
||||
if (d.length != range.length) return nil;
|
||||
return d;
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
return nil;
|
||||
@@ -428,7 +475,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
}
|
||||
|
||||
///
|
||||
/// Retrieve quarantine data for a file
|
||||
/// Retrieve quarantine data for a file and caches the dictionary
|
||||
///
|
||||
- (NSDictionary *)quarantineData {
|
||||
if (!self.quarantineDict && NSURLQuarantinePropertiesKey != NULL) {
|
||||
@@ -459,6 +506,13 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
return nil;
|
||||
}
|
||||
|
||||
///
|
||||
/// Resolves a given path:
|
||||
/// + Follows symlinks
|
||||
/// + Converts relative paths to absolute
|
||||
/// + If path is a directory, checks to see if that directory is a bundle and if so
|
||||
/// returns the path to that bundles CFBundleExecutable.
|
||||
///
|
||||
- (NSString *)resolvePath:(NSString *)path {
|
||||
// Convert to absolute, standardized path
|
||||
path = [path stringByResolvingSymlinksInPath];
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
/// Config ops
|
||||
///
|
||||
- (void)clientMode:(void (^)(santa_clientmode_t))reply;
|
||||
- (void)watchdogCPUEvents:(void (^)(uint64_t))reply;
|
||||
- (void)watchdogRAMEvents:(void (^)(uint64_t))reply;
|
||||
- (void)watchdogInfo:(void (^)(uint64_t, uint64_t, double, double))reply;
|
||||
- (void)setClientMode:(santa_clientmode_t)mode reply:(void (^)())reply;
|
||||
- (void)setNextSyncInterval:(uint64_t)seconds reply:(void (^)())reply;
|
||||
- (void)setSyncLastSuccess:(NSDate *)date reply:(void (^)())reply;
|
||||
|
||||
@@ -116,8 +116,11 @@ void SantaDecisionManager::DisconnectClient(bool itDied) {
|
||||
|
||||
bool SantaDecisionManager::ClientConnected() {
|
||||
proc_t p = proc_find(client_pid_);
|
||||
bool is_exiting = proc_exiting(p);
|
||||
proc_rele(p);
|
||||
bool is_exiting = false;
|
||||
if (p) {
|
||||
is_exiting = proc_exiting(p);
|
||||
proc_rele(p);
|
||||
}
|
||||
return (client_pid_ > 0 && !is_exiting);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,14 +60,17 @@ REGISTER_COMMAND_NAME(@"binaryinfo")
|
||||
}
|
||||
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
dateFormatter.dateFormat = @"YYYY/MM/dd HH:mm:ss Z";
|
||||
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss Z";
|
||||
|
||||
[self printKey:@"Path" value:fileInfo.path];
|
||||
[self printKey:@"SHA-256" value:fileInfo.SHA256];
|
||||
[self printKey:@"SHA-1" value:fileInfo.SHA1];
|
||||
[self printKey:@"Bundle Name" value:fileInfo.bundleName];
|
||||
[self printKey:@"Bundle Version" value:fileInfo.bundleVersion];
|
||||
[self printKey:@"Bundle Version Str" value:fileInfo.bundleShortVersionString];
|
||||
|
||||
if (fileInfo.bundlePath) {
|
||||
[self printKey:@"Bundle Name" value:fileInfo.bundleName];
|
||||
[self printKey:@"Bundle Version" value:fileInfo.bundleVersion];
|
||||
[self printKey:@"Bundle Version Str" value:fileInfo.bundleShortVersionString];
|
||||
}
|
||||
|
||||
if (fileInfo.quarantineDataURL) {
|
||||
[self printKey:@"Download Referer URL" value:fileInfo.quarantineRefererURL];
|
||||
|
||||
@@ -48,6 +48,7 @@ REGISTER_COMMAND_NAME(@"status")
|
||||
// Daemon status
|
||||
__block NSString *clientMode;
|
||||
__block uint64_t cpuEvents, ramEvents;
|
||||
__block double cpuPeak, ramPeak;
|
||||
dispatch_group_enter(group);
|
||||
[[daemonConn remoteObjectProxy] clientMode:^(santa_clientmode_t cm) {
|
||||
switch (cm) {
|
||||
@@ -61,15 +62,15 @@ REGISTER_COMMAND_NAME(@"status")
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
dispatch_group_enter(group);
|
||||
[[daemonConn remoteObjectProxy] watchdogCPUEvents:^(uint64_t events) {
|
||||
cpuEvents = events;
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
dispatch_group_enter(group);
|
||||
[[daemonConn remoteObjectProxy] watchdogRAMEvents:^(uint64_t events) {
|
||||
ramEvents = events;
|
||||
[[daemonConn remoteObjectProxy] watchdogInfo:^(uint64_t wd_cpuEvents, uint64_t wd_ramEvents,
|
||||
double wd_cpuPeak, double wd_ramPeak) {
|
||||
cpuEvents = wd_cpuEvents;
|
||||
cpuPeak = wd_cpuPeak;
|
||||
ramEvents = wd_ramEvents;
|
||||
ramPeak = wd_ramPeak;
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
|
||||
BOOL fileLogging = ([[SNTConfigurator configurator] fileChangesRegex] != nil);
|
||||
|
||||
// Kext status
|
||||
@@ -97,7 +98,7 @@ REGISTER_COMMAND_NAME(@"status")
|
||||
// Sync status
|
||||
NSString *syncURLStr = [[[SNTConfigurator configurator] syncBaseURL] absoluteString];
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
dateFormatter.dateFormat = @"YYYY/MM/dd HH:mm:ss Z";
|
||||
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss Z";
|
||||
NSDate *lastSyncSuccess = [[SNTConfigurator configurator] syncLastSuccess];
|
||||
NSString *lastSyncSuccessStr = [dateFormatter stringFromDate:lastSyncSuccess] ?: @"Never";
|
||||
BOOL syncCleanReqd = [[SNTConfigurator configurator] syncCleanRequired];
|
||||
@@ -114,6 +115,8 @@ REGISTER_COMMAND_NAME(@"status")
|
||||
@"file_logging": @(fileLogging),
|
||||
@"watchdog_cpu_events": @(cpuEvents),
|
||||
@"watchdog_ram_events": @(ramEvents),
|
||||
@"watchdog_cpu_peak": @(cpuPeak),
|
||||
@"watchdog_ram_peak": @(ramPeak),
|
||||
},
|
||||
@"kernel": @{
|
||||
@"cache_count": @(cacheCount),
|
||||
@@ -138,8 +141,8 @@ REGISTER_COMMAND_NAME(@"status")
|
||||
printf(">>> Daemon Info\n");
|
||||
printf(" %-22s | %s\n", "Mode", [clientMode UTF8String]);
|
||||
printf(" %-22s | %s\n", "File Logging", (fileLogging ? "Yes" : "No"));
|
||||
printf(" %-22s | %lld\n", "Watchdog CPU Events", cpuEvents);
|
||||
printf(" %-22s | %lld\n", "Watchdog RAM Events", ramEvents);
|
||||
printf(" %-22s | %lld (Peak: %.2f%%)\n", "Watchdog CPU Events", cpuEvents, cpuPeak);
|
||||
printf(" %-22s | %lld (Peak: %.2fMB)\n", "Watchdog RAM Events", ramEvents, ramPeak);
|
||||
printf(">>> Kernel Info\n");
|
||||
printf(" %-22s | %lld\n", "Kernel cache count", cacheCount);
|
||||
printf(">>> Database Info\n");
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
// Globals used by the santad watchdog thread
|
||||
uint64_t watchdogCPUEvents = 0;
|
||||
uint64_t watchdogRAMEvents = 0;
|
||||
double watchdogCPUPeak = 0;
|
||||
double watchdogRAMPeak = 0;
|
||||
|
||||
@interface SNTDaemonControlController ()
|
||||
@property dispatch_source_t syncTimer;
|
||||
@@ -172,12 +174,8 @@ uint64_t watchdogRAMEvents = 0;
|
||||
reply();
|
||||
}
|
||||
|
||||
- (void)watchdogCPUEvents:(void (^)(uint64_t))reply {
|
||||
reply(watchdogCPUEvents);
|
||||
}
|
||||
|
||||
- (void)watchdogRAMEvents:(void (^)(uint64_t))reply {
|
||||
reply(watchdogRAMEvents);
|
||||
- (void)watchdogInfo:(void (^)(uint64_t, uint64_t, double, double))reply {
|
||||
reply(watchdogCPUEvents, watchdogRAMEvents, watchdogCPUPeak, watchdogRAMPeak);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,10 +21,12 @@
|
||||
|
||||
extern uint64_t watchdogCPUEvents;
|
||||
extern uint64_t watchdogRAMEvents;
|
||||
extern double watchdogCPUPeak;
|
||||
extern double watchdogRAMPeak;
|
||||
|
||||
/// Converts a timeval struct to double, converting the microseconds value to seconds.
|
||||
static inline double timeval_to_double(struct timeval tv) {
|
||||
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
|
||||
static inline double timeval_to_double(time_value_t tv) {
|
||||
return (double)tv.seconds + (double)tv.microseconds / 1000000.0;
|
||||
}
|
||||
|
||||
/// The watchdog thread function, used to monitor santad CPU/RAM usage and print a warning
|
||||
@@ -45,36 +47,39 @@ void *watchdogThreadFunction(__unused void *idata) {
|
||||
|
||||
double prevTotalTime = 0.0;
|
||||
double prevRamUseMB = 0.0;
|
||||
struct rusage usage;
|
||||
struct mach_task_basic_info taskInfo;
|
||||
mach_msg_type_number_t taskInfoCount = MACH_TASK_BASIC_INFO_COUNT;
|
||||
|
||||
while(true) {
|
||||
@autoreleasepool {
|
||||
sleep(timeInterval);
|
||||
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
|
||||
(task_info_t)&taskInfo, &taskInfoCount) == KERN_SUCCESS) {
|
||||
// CPU
|
||||
double totalTime = (timeval_to_double(taskInfo.user_time) +
|
||||
timeval_to_double(taskInfo.system_time));
|
||||
double percentage = (((totalTime - prevTotalTime) / (double)timeInterval) * 100.0);
|
||||
prevTotalTime = totalTime;
|
||||
|
||||
// CPU
|
||||
getrusage(RUSAGE_SELF, &usage);
|
||||
double totalTime = timeval_to_double(usage.ru_utime) + timeval_to_double(usage.ru_stime);
|
||||
double percentage = (((totalTime - prevTotalTime) / (double)timeInterval) * 100.0);
|
||||
prevTotalTime = totalTime;
|
||||
if (percentage > cpuWarnThreshold) {
|
||||
LOGW(@"Watchdog: potentially high CPU use, ~%.2f%% over last %d seconds.",
|
||||
percentage, timeInterval);
|
||||
watchdogCPUEvents++;
|
||||
}
|
||||
|
||||
if (percentage > cpuWarnThreshold) {
|
||||
LOGW(@"Watchdog: potentially high CPU use, ~%.2f%% over last %d seconds.",
|
||||
percentage, timeInterval);
|
||||
watchdogCPUEvents++;
|
||||
}
|
||||
if (percentage > watchdogCPUPeak) watchdogCPUPeak = percentage;
|
||||
|
||||
// RAM
|
||||
if (KERN_SUCCESS == task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
|
||||
(task_info_t)&taskInfo, &taskInfoCount)) {
|
||||
double ramUseMB = (double) taskInfo.resident_size / 1024 / 1024;
|
||||
// RAM
|
||||
double ramUseMB = (double)taskInfo.resident_size / 1024 / 1024;
|
||||
if (ramUseMB > memWarnThreshold && ramUseMB > prevRamUseMB) {
|
||||
LOGW(@"Watchdog: potentially high RAM use, RSS is %.2fMB.", ramUseMB);
|
||||
watchdogRAMEvents++;
|
||||
}
|
||||
prevRamUseMB = ramUseMB;
|
||||
|
||||
if (ramUseMB > watchdogRAMPeak) watchdogRAMPeak = ramUseMB;
|
||||
}
|
||||
|
||||
sleep(timeInterval);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
Reference in New Issue
Block a user