init: logd: Allow Developer settings to adjust logd size

- AID_SYSTEM can set persist.logd.size
- AID_SYSTEM can issue command to /dev/socket/logd to
  change the runtime global log sizes.
- Add support for ro.logd.size.* as populated by BoardConfig.mk
- Limit size to maximum ~3% of physical memory.

Bug: 14563261
Bug: 14627052
Change-Id: I606420db2e9d9d032296e71149e4a5b20cbd1137
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index dc9d47e..ae167aa 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/user.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -32,6 +33,34 @@
 // Default
 #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
 #define log_buffer_size(id) mMaxSize[id]
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+
+static bool valid_size(unsigned long value) {
+    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+        return false;
+    }
+
+    long pages = sysconf(_SC_PHYS_PAGES);
+    if (pages < 1) {
+        return true;
+    }
+
+    long pagesize = sysconf(_SC_PAGESIZE);
+    if (pagesize <= 1) {
+        pagesize = PAGE_SIZE;
+    }
+
+    // maximum memory impact a somewhat arbitrary ~3%
+    pages = (pages + 31) / 32;
+    unsigned long maximum = pages * pagesize;
+
+    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+        return true;
+    }
+
+    return value <= maximum;
+}
 
 static unsigned long property_get_size(const char *key) {
     char property[PROPERTY_VALUE_MAX];
@@ -56,6 +85,10 @@
         value = 0;
     }
 
+    if (!valid_size(value)) {
+        value = 0;
+    }
+
     return value;
 }
 
@@ -64,18 +97,38 @@
     pthread_mutex_init(&mLogElementsLock, NULL);
     dgram_qlen_statistics = false;
 
-    static const char global_default[] = "persist.logd.size";
-    unsigned long default_size = property_get_size(global_default);
+    static const char global_tuneable[] = "persist.logd.size"; // Settings App
+    static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
+
+    unsigned long default_size = property_get_size(global_tuneable);
+    if (!default_size) {
+        default_size = property_get_size(global_default);
+    }
 
     log_id_for_each(i) {
-        setSize(i, LOG_BUFFER_SIZE);
-        setSize(i, default_size);
-
         char key[PROP_NAME_MAX];
-        snprintf(key, sizeof(key), "%s.%s",
-                 global_default, android_log_id_to_name(i));
 
-        setSize(i, property_get_size(key));
+        snprintf(key, sizeof(key), "%s.%s",
+                 global_tuneable, android_log_id_to_name(i));
+        unsigned long property_size = property_get_size(key);
+
+        if (!property_size) {
+            snprintf(key, sizeof(key), "%s.%s",
+                     global_default, android_log_id_to_name(i));
+            property_size = property_get_size(key);
+        }
+
+        if (!property_size) {
+            property_size = default_size;
+        }
+
+        if (!property_size) {
+            property_size = LOG_BUFFER_SIZE;
+        }
+
+        if (setSize(i, property_size)) {
+            setSize(i, LOG_BUFFER_MIN_SIZE);
+        }
     }
 }
 
@@ -339,7 +392,7 @@
 // set the total space allocated to "id"
 int LogBuffer::setSize(log_id_t id, unsigned long size) {
     // Reasonable limits ...
-    if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
+    if (!valid_size(size)) {
         return -1;
     }
     pthread_mutex_lock(&mLogElementsLock);