liblog: add IF_ALOG_RATELIMIT

IF_ALOG_RATELIMIT()
    ALOGE("Only one message globally using IF_ALOG_RATELIMIT()"
          " in the process may appear ever ten seconds,"
          " (%s)", strerror(errno));

static time_t last; /* initial state zero */
IF_ALOG_RATELIMIT_LOCAL(60, &last)
    ALOGE("Only one message locally may appear every minute,"
          " (%s)", strerror(errno));

These new calls are guaranteed not to affect the value of a
non-zero errno to simplify logging of errors.  However, the
ALOGE calls in the above examples may update the errno value
upon their return.

Test: gTest liblog-unit-tests --gtest_filter=liblog.__android_log_ratelimit
Bug: 33535908
Change-Id: Id8cc192fc7d14504ffd418933cf88ae945c089f2
diff --git a/include/log/log.h b/include/log/log.h
index d6f0eb5..ece9ea6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -24,7 +24,7 @@
 #include <stdint.h>  /* uint16_t, int32_t */
 #include <stdio.h>
 #include <sys/types.h>
-#include <time.h>    /* clock_gettime */
+#include <time.h>
 #include <unistd.h>
 
 #include <android/log.h>
@@ -812,6 +812,54 @@
 void __android_log_close();
 #endif
 
+#ifndef __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1
+#elif __ANDROID_API__ > 25 /* > OC */
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
+
+/*
+ * if last is NULL, caller _must_ provide a consistent value for seconds.
+ *
+ * Return -1 if we can not acquire a lock, which below will permit the logging,
+ * error on allowing a log message through.
+ */
+int __android_log_ratelimit(time_t seconds, time_t* last);
+
+/*
+ * Usage:
+ *
+ *   // Global default and state
+ *   IF_ALOG_RATELIMIT() {
+ *      ALOG*(...);
+ *   }
+ *
+ *   // local state, 10 seconds ratelimit
+ *   static time_t local_state;
+ *   IF_ALOG_RATELIMIT_LOCAL(10, &local_state) {
+ *     ALOG*(...);
+ *   }
+ */
+
+#define IF_ALOG_RATELIMIT() \
+      if (__android_log_ratelimit(0, NULL) > 0)
+#define IF_ALOG_RATELIMIT_LOCAL(seconds, state) \
+      if (__android_log_ratelimit(seconds, state) > 0)
+
+#else
+
+/* No ratelimiting as API unsupported */
+#define IF_ALOG_RATELIMIT() if (1)
+#define IF_ALOG_RATELIMIT_LOCAL(...) if (1)
+
+#endif
+
 #if defined(__clang__)
 #pragma clang diagnostic pop
 #endif