Cómo obtener el tiempo de actividad del sistema iOS, que no se detiene cuando está dormido

Estoy buscando una forma de obtener un tiempo de actividad del sistema absoluto y siempre creciente en iOS.

Debería devolver el tiempo transcurrido desde que se reinició el dispositivo por última vez, y no verse afectado por cambios en la fecha del sistema.

Todos los métodos que puedo encontrar se pausan cuando el dispositivo está dormido (CACurrentMediaTime, [NSProcessInfo systemUptime], mach_absolute_time) o cambian cuando la fecha del sistema cambia (sysctl / KERN_BOOTTIME).

¿Algunas ideas?

Creo que lo resolví.

time () continúa incrementándose mientras el dispositivo está dormido, pero por supuesto puede ser manipulado por el sistema operativo o el usuario. Sin embargo, el Kernel boottime (una marca de tiempo de cuando el sistema arrancó por última vez) también cambia cuando se cambia el reloj del sistema, por lo tanto, aunque ambos valores no son fijos, la diferencia entre ellos es.

#include  - (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; } 

Hay una condición de carrera en todos los ejemplos enumerados: si hay un cambio de hora (NTP o modificado por el usuario), el código correrá y el reloj ya no será monótono.

La implementación correcta es:

 #include  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; } 

Como se dijo en uno de los comentarios, clock_gettime() POSIX se implementó en iOS 10 y macOS 10.12. Cuando se utiliza con el argumento CLOCK_MONOTONIC , parece devolver el valor de tiempo de actividad. Sin embargo, esto no está garantizado por la documentación:

Para este reloj, el valor devuelto por clock_gettime () representa la cantidad de tiempo (en segundos y nanosegundos) desde un punto no especificado en el pasado (por ejemplo, el tiempo de inicio del sistema o la Época). Este punto no cambia después del tiempo de inicio del sistema.

Y un extracto de la página man correspondiente de macOS:

Reloj CLOCK_MONOTONIC que se incrementa monótonamente, rastreando el tiempo desde un punto arbitrario, y continuará incrementándose mientras el sistema está dormido.

CLOCK_MONOTONIC_RAW reloj que se incrementa monótonamente, rastreando el tiempo desde un punto arbitrario como CLOCK_MONOTONIC. Sin embargo, este reloj no se ve afectado por los ajustes de frecuencia o tiempo. No se debe comparar con otras fonts de tiempo del sistema.

CLOCK_MONOTONIC_RAW_APPROX como CLOCK_MONOTONIC_RAW, pero lee un valor almacenado en caché por el sistema en el cambio de contexto. Esto se puede leer más rápido, pero con una pérdida de precisión, ya que puede devolver valores que son milisegundos anteriores.

CLOCK_UPTIME_RAW reloj que se incrementa monótonamente, de la misma manera que CLOCK_MONOTONIC_RAW, pero que no aumenta mientras el sistema está dormido. El valor devuelto es idéntico al resultado de mach_absolute_time () después de aplicar la conversión mach_timebase apropiada.

Tenga en cuenta que CLOCK_MONOTONIC regresa con una precisión de microsegundos mientras CLOCK_MONOTONIC_RAW con precisión de nanosegundos.

Código 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) 

Para aquellos que aún estén interesados ​​en obtener el tiempo de arranque del kernel en Swift:

 func kernelBootTime() -> timeval { var mib = [ CTL_KERN, KERN_BOOTTIME ] var bootTime = timeval() var bootTimeSize = MemoryLayout.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) 

Si se necesita una mayor precisión, a continuación se encuentra una versión modificada de la respuesta aceptada.

 #include  - (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; } 

Yo comentaría la respuesta de Leszek, pero no la repetición suficiente … La solución de Leszek devuelve segundos.

La siguiente es una versión modificada de la respuesta de Leszek si alguien necesita una precisión de milisegundos.

 #include  + (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; } 

¿Por qué no usar SystemUptime ?

systemUptime Devuelve cuánto tiempo ha pasado desde que se reinició la computadora.

  • (NSTimeInterval) systemUptime Return Value Un NSTimeInterval que indica cuánto tiempo desde que se reinició la computadora.

Disponibilidad Disponible en iOS 4.0 y posterior. Declarado en NSProcessInfo.h

He probado y probado que, al menos en el iPhone 5 con iOS 7.1.1, el tiempo de sistema no se detiene cuando el teléfono está bloqueado. Entonces, cualquiera no cree que esto pueda probarlo usted mismo.

    Intereting Posts