Po Lu wrote:
> > Also, I don't know how Android records boot time so I'll cc this to Po
> > Lu, the main developer for Emacs on Android.
> 
> The boot time is off limits to user programs on Android, for security
> reasons.

No, it isn't. The attached file, when compiled and run under Termux (which
doesn't have particular permissions), prints e.g.:

from clock  : 1691616762.476870660 = 2023-08-09 21:32:42.476870660
from sysinfo: 1691616762.329261637 = 2023-08-09 21:32:42.329261637

Note that this uses the kernel's uptime counter, so it will not work well
when the user changes the current time manually. But this is rare on Android.

Bruno
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/sysinfo.h>

static const char *
as_time_string (time_t tim)
{
  struct tm *gmt = gmtime (&tim);
  static char timbuf[100];
  if (gmt == NULL
      || strftime (timbuf, sizeof (timbuf), "%Y-%m-%d %H:%M:%S", gmt)
         == 0)
    strcpy (timbuf, "---");
  return timbuf;
}

int main ()
{
  /* clock() returns the uptime with a resolution of ca. 1 usec.  */
  struct timespec ts_now;
  struct timespec up;
  if (clock_gettime (CLOCK_REALTIME, &ts_now) == 0
      && clock_gettime (CLOCK_BOOTTIME, &up) == 0)
    {
      struct timespec result = ts_now;

      if (result.tv_nsec < up.tv_nsec)
        {
          result.tv_nsec += 1000000000;
          result.tv_sec -= 1;
        }
      result.tv_sec -= up.tv_sec;
      result.tv_nsec -= up.tv_nsec;
      printf ("from clock  : %d.%09d = %s.%09d\n",
              (int) result.tv_sec, (int) result.tv_nsec,
              as_time_string (result.tv_sec), (int) result.tv_nsec);
    }

  /* /proc/uptime contains the uptime with a resolution of 0.01 sec.  */
  FILE *fp = fopen ("/proc/uptime", "re");
  if (fp != NULL)
    {
      char buf[32 + 1];
      size_t n = fread (buf, 1, sizeof (buf) - 1, fp);
      fclose (fp);
      if (n > 0)
        {
          buf[n] = '\0';
          /* buf now contains two values: the uptime and the idle time.  */
          char *endptr;
          double uptime = strtod (buf, &endptr);
          if (endptr > buf)
            {
              struct timespec result;
              if (clock_gettime (CLOCK_REALTIME, &result) == 0)
                {
                  time_t uptime_sec = uptime;
                  struct timespec up =
                    {
                      .tv_sec = uptime_sec,
                      .tv_nsec = (uptime - uptime_sec) * 1e9 + 0.5
                    };
                  if (result.tv_nsec < up.tv_nsec)
                    {
                      result.tv_nsec += 1000000000;
                      result.tv_sec -= 1;
                    }
                  result.tv_sec -= up.tv_sec;
                  result.tv_nsec -= up.tv_nsec;
                  printf ("from /proc  : %d.%09d = %s.%09d\n",
                          (int) result.tv_sec, (int) result.tv_nsec,
                          as_time_string (result.tv_sec), (int) result.tv_nsec);
                }
            }
        }
    }

  /* The sysinfo call returns the uptime with a resolution of 1 sec only.  */
  struct sysinfo info;
  if (sysinfo (&info) >= 0)
    {
      struct timespec result;
      if (clock_gettime (CLOCK_REALTIME, &result) == 0)
        {
          result.tv_sec -= info.uptime;
          printf ("from sysinfo: %d.%09d = %s.%09d\n",
                  (int) result.tv_sec, (int) result.tv_nsec,
                  as_time_string (result.tv_sec), (int) result.tv_nsec);
        }
    }

  return 0;
}

Reply via email to