2012-09-19 7 views
31

Szukam sposobu na uzyskanie bezwzględnego, zawsze zwiększającego się czasu pracy systemu na iOS.Uzyskiwanie czasu pracy systemu iOS, który nie zatrzymuje się podczas snu

Powinno zwrócić czas od ostatniego ponownego uruchomienia urządzenia i nie może być zmienione w dacie systemowej.

Wszystkie metody mogę znaleźć albo wstrzymać, gdy urządzenie jest w trybie uśpienia (CACurrentMediaTime, [NSProcessInfo systemUptime] mach_absolute_time) lub są zmieniane, gdy zmienia się data systemowa (sysctl/KERN_BOOTTIME).

Wszelkie pomysły?

Odpowiedz

45

Myślę, że to rozwiązałem.

time() wykonuje inkrementację w czasie, gdy urządzenie śpi, ale oczywiście można nim manipulować przez system operacyjny lub użytkownika. Jednakże bajt jądra (znacznik czasu, w którym system ostatnio uruchomił się) również zmienia się po zmianie zegara systemowego, dlatego też, mimo że obie te wartości nie są stałe, przesunięcie między nimi jest.

#include <sys/sysctl.h> 

- (time_t)uptime 
{ 
    struct timeval boottime; 

    int mib[2] = {CTL_KERN, KERN_BOOTTIME}; 

    size_t size = sizeof(boottime); 

    time_t now; 

    time_t uptime = -1; 

    (void)time(&now); 

    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) 

    { 

     uptime = now - boottime.tv_sec; 

    } 



    return uptime; 

} 
+0

Brawo kolego. Miałem iść na randkę z datą serwera/lokalną datą porównania przed tym ... Tak bardzo doceniane. – Magoo

+1

Myślę, że to nie działa na symulatorze. – mkeremkeskin

+0

Zgadza się. –

-6

Dlaczego nie używając systemUptime?

systemUptime Zwraca czas, jaki upłynął od ponownego uruchomienia komputera.

  • (NSTimeInterval) systemUptime Return Value NSTimeInterval wskazuje jak długo ponieważ komputer został uruchomiony ponownie.

Dostępność Dostępne w iOS 4.0 i nowszych. zadeklarowane w NSProcessInfo.h

mam przetestowane i okazało się, że przynajmniej na iPhone 5 z iOS 7.1.1, systemUptime nie zatrzymuje się, gdy telefon jest zablokowany. Więc każdy nie wierzy, że to może przetestować to samemu.

+0

W moim teście z iOS 7.1.x. Nie zatrzymuje się, gdy urządzenie jest zablokowane, a ekran jest wyłączony. –

+0

ma to wpływ na sen/czuwanie, naprawdę. Może przetestowałeś go z podłączonym kablem, który zapobiega snu. Albo jakiś inny blok powodujący spanie twojego urządzenia podczas testowania ... – Speakus

+0

Tak, przeszedłem test i przestaje, przepraszam. –

3

Jeśli wymagana jest wyższa precyzja, poniżej jest zmodyfikowana wersja zaakceptowanej odpowiedzi.

#include <sys/sysctl.h> 

- (NSTimeInterval)uptime 
{ 
    struct timeval boottime; 
    int mib[2] = {CTL_KERN, KERN_BOOTTIME}; 
    size_t size = sizeof(boottime); 

    struct timeval now; 
    struct timezone tz; 
    gettimeofday(&now, &tz); 

    double uptime = -1; 

    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) 
    { 
     uptime = now.tv_sec - boottime.tv_sec; 
     uptime += (double)(now.tv_usec - boottime.tv_usec)/1000000.0; 
    } 
    return uptime; 
} 
10

Jest to warunek wyścig we wszystkich przykładach wymieniono: czy istnieje zmiana czasu (NTP lub zmodyfikowane przez użytkownika), kod będzie ścigać i zegar nie jest monotonna.

Prawidłowa realizacja jest:

#include <sys/sysctl.h> 

static int64_t us_since_boot() { 
    struct timeval boottime; 
    int mib[2] = {CTL_KERN, KERN_BOOTTIME}; 
    size_t size = sizeof(boottime); 
    int rc = sysctl(mib, 2, &boottime, &size, NULL, 0); 
    if (rc != 0) { 
     return 0; 
    } 
    return (int64_t)boottime.tv_sec * 1000000 + (int64_t)boottime.tv_usec; 
} 

- (int64_t)us_uptime 
{ 
    int64_t before_now; 
    int64_t after_now; 
    struct timeval now; 

    after_now = us_since_boot(); 
    do { 
     before_now = after_now; 
     gettimeofday(&now, NULL); 
     after_now = us_since_boot(); 
    } while (after_now != before_now); 

    return (int64_t)now.tv_sec * 1000000 + (int64_t)now.tv_usec - before_now; 
} 
+4

Testowałem to i wygląda na to, że działa jak urok. Nie mogę znaleźć w nim żadnych błędów. Dzięki! Dla przypomnienia, w końcu istnieje niezgrabne rozwiązanie dla OS10 i wyższych. Interfejs API clock_gettime jest już dostępny i korzystanie z CLOCK_MONOTONIC powinno obsługiwać wymagania dotyczące monotonicznego zegara, który zwiększa się przy częstotliwości zegara ściennego z przyzwoitą dokładnością. –

+0

To jest świetne, z wyjątkiem nazwy funkcji 'us_since_boot'. To tylko czas rozruchu, nie upłynął czas od rozruchu. –

+0

Należy zauważyć, że istnieje możliwość wystąpienia przepełnienia podczas wykonywania 'boottime.tv_sec * 1000000' lub' now.tv_sec * 1000000' (na platformach 32-bitowych jest to łatwe do przechwycenia). Aby uniknąć tego problemu, musisz wykonać bezpośrednią obsadę. – d12frosted

2

będę komentować odpowiedzi Leszka, ale nie na tyle rep ... rozwiązanie Leszka zwraca sekund.

Poniżej znajduje się zmodyfikowana wersja odpowiedzi Leszka, jeśli ktoś potrzebuje milisekundy precyzji.

#include <sys/sysctl.h> 

+ (long long int)uptime 
{ 
    struct timeval boottime; 
    int mib[2] = {CTL_KERN, KERN_BOOTTIME}; 
    size_t size = sizeof(boottime); 

    struct timeval now; 
    struct timezone tz; 
    gettimeofday(&now, &tz); 

    long long int uptime = -1; 

    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) 
    { 
     uptime = ((long long int)(now.tv_sec - boottime.tv_sec)) * 1000; 
     uptime += (now.tv_usec - boottime.tv_usec)/1000; 
    } 
    return uptime; 
} 
3

Jak powiedział w jednym z komentarzy, POSIX'sclock_gettime() został wdrożony w iOS 10 i MacOS 10.12. W przypadku użycia z argumentem CLOCK_MONOTONIC, wydaje się, że zwraca wartość czasu pracy.Jednakże, nie jest to zagwarantowane dokumentacji:

tego zegara wartość zwrócony przez clock_gettime() reprezentuje czas (w sekundach i nanosekund) od nieokreślonym punkcie w przeszłości (na przykład , czas uruchomienia systemu lub Epoka). Ten punkt nie zmienia się po czasie uruchomienia systemu.

i wyciąg z odpowiedniego stronie MacOS człowieka:

CLOCK_MONOTONIC zegar, który zwiększa monotonicznie, śledzenie czasu od dowolnego punktu, i będzie nadal zwiększać, gdy system jest w trybie uśpienia.

CLOCK_MONOTONIC_RAW Zegar, który zwiększa monotonicznie, śledząc czas od dowolnego punktu, takiego jak CLOCK_MONOTONIC. Jednak ten zegar nie ma wpływu na regulację częstotliwości ani czasu. Nie należy go porównywać z innymi systemowymi źródłami czasu.

CLOCK_MONOTONIC_RAW_APPROX jak CLOCK_MONOTONIC_RAW, ale odczytuje wartość buforowane przez system na kontekst przełącznika. Można to odczytać szybciej, ale z mniejszą dokładnością, ponieważ może zwracać wartości, które są w milisekundach stare.

CLOCK_UPTIME_RAW zegar, który powiększa się monotonicznie w taki sam sposób jak CLOCK_MONOTONIC_RAW, ale to nie ma przyrostu, gdy system jest w trybie uśpienia. Zwrócona wartość jest identyczna z wynikiem mach_absolute_time() po zastosowaniu odpowiedniej konwersji mach_timebase.

pamiętać, że CLOCK_MONOTONIC powraca z precyzją mikrosekund podczas CLOCK_MONOTONIC_RAW z precyzją nanosekund.

Kod Swift:

func uptime() -> timespec { 

    var uptime = timespec() 
    if 0 != clock_gettime(CLOCK_MONOTONIC_RAW, &uptime) { 
     fatalError("Could not execute clock_gettime, errno: \(errno)") 
    } 

    return uptime 
} 

print(uptime()) // timespec(tv_sec: 636705, tv_nsec: 750700397) 

Dla tych, nadal zainteresowany dostając czas uruchamiania jądra w Swift:

func kernelBootTime() -> timeval { 

    var mib = [ CTL_KERN, KERN_BOOTTIME ] 
    var bootTime = timeval() 
    var bootTimeSize = MemoryLayout<timeval>.size 

    if 0 != sysctl(&mib, UInt32(mib.count), &bootTime, &bootTimeSize, nil, 0) { 
     fatalError("Could not get boot time, errno: \(errno)") 
    } 

    return bootTime 
} 

print(kernelBootTime()) // timeval(tv_sec: 1499259206, tv_usec: 122778)