做一個流量監控,之前的代碼是通過sysctl讀取進程列表,取得kernel_task進程的啓動時間作爲系統啓動時間,如果系統重啓就需要把網卡記錄的流量全部累加,否則用本次讀取的網卡流量數據減去上一次記錄的數據認爲是這段時間內用戶產生的流量。
在iOS9上 sysctl被封了,於是這段代碼就掛了。沒辦法拿到系統啓動時間,就會不停的累加網卡記錄的全部流量。
使用sysctl取得kernel_task啓動時間
+ (NSDate *)systemStartTime
{
size_t length = 0;
static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
int err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
if (err == -1)
{
err = errno;
}
if (err == 0)
{
struct kinfo_proc *procBuffer = (struct kinfo_proc *)malloc(length);
if(procBuffer == NULL)
{
return nil;
}
sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, procBuffer, &length, NULL, 0);
int count = (int)length / sizeof(struct kinfo_proc);
for (int i = 0; i < count; ++i)
{
NSString *procName = [NSString stringWithCString:procBuffer[i].kp_proc.p_comm encoding:NSUTF8StringEncoding];
if ([procName isEqualToString:@"kernel_task"])
{
return [NSDate dateWithTimeIntervalSince1970:procBuffer[i].kp_proc.p_un.__p_starttime.tv_sec];
}
}
}
return nil;
}
使用sysctlbyname取得boottime
+ (NSDate *)systemStartTime {
size_t size;
sysctlbyname("kern.boottime", NULL, &size, NULL, 0);
char *boot_time = malloc(size);
sysctlbyname("kern.boottime", boot_time, &size, NULL, 0);
uint32_t timestamp = 0;
memcpy(×tamp, boot_time, sizeof(uint32_t));
free(boot_time);
NSDate* bootTime = [NSDate dateWithTimeIntervalSince1970:timestamp];
NSLog(@"BootTime: %@", bootTime);
return bootTime;
}
boottime 也是有問題的,就是用戶手動設置系統時間後,bootime會變動成手動設置的那個時刻;另外mach_absolute_time讀取出來的tick數和bootime是一致的,個人猜測boottime其實就是換算mach_absolute_time()的結果。