天天看點

iOS 擷取系統啟動時間

做一個流量監控,之前的代碼是通過sysctl讀取程序清單,取得kernel_task程序的啟動時間作為系統啟動時間,如果系統重新開機就需要把網卡記錄的流量全部累加,否則用本次讀取的網卡流量資料減去上一次記錄的資料認為是這段時間内使用者産生的流量。

在iOS9上 sysctl被封了,于是這段代碼就挂了。沒辦法拿到系統啟動時間,就會不停的累加網卡記錄的全部流量。

使用sysctl取得kernel_task啟動時間

+ (NSDate *)systemStartTime
{
    size_t length = ;
    static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, };
    int err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - , NULL, &length, NULL, );
    if (err == -)
    {
        err = errno;
    }
    if (err == )
    {
        struct kinfo_proc *procBuffer = (struct kinfo_proc *)malloc(length);
        if(procBuffer == NULL)
        {
            return nil;
        }

        sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - , procBuffer, &length, NULL, );

        int count = (int)length / sizeof(struct kinfo_proc);
        for (int i = ; 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, );
    char *boot_time = malloc(size);
    sysctlbyname("kern.boottime", boot_time, &size, NULL, );
    uint32_t timestamp = ;
    memcpy(&timestamp, 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()的結果。