Add callback hack to find out when to reload system properties.

Every IBinder object can accept a new transaction to tell it that
it might want to reload system properties, and in the process
anyone can register a callback to be executed when this happens.

Use this to reload the trace property.

This is very much ONLY for debugging.

Change-Id: I55c67c46f8f3fa9073bef0dfaab4577ed1d47eb4
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index 62f5d6b..984cd46 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -121,11 +121,16 @@
         }
     }
 
+    static void changeCallback();
+
     // init opens the trace marker file for writing and reads the
     // atrace.tags.enableflags system property.  It does this only the first
     // time it is run, using sMutex for synchronization.
     static void init();
 
+    // retrieve the current value of the system property.
+    static void loadSystemProperty();
+
     // sIsReady is a boolean value indicating whether a call to init() has
     // completed in this process.  It is initialized to 0 and set to 1 when the
     // first init() call completes.  It is set to 1 even if a failure occurred
diff --git a/include/utils/misc.h b/include/utils/misc.h
index 23f2a4c..d7d5bc1 100644
--- a/include/utils/misc.h
+++ b/include/utils/misc.h
@@ -88,6 +88,10 @@
 void k_itoa(int value, char* str, int base);
 char* itoa(int val, int base);
 
+typedef void (*sysprop_change_callback)(void);
+void add_sysprop_change_callback(sysprop_change_callback cb, int priority);
+void report_sysprop_change();
+
 }; // namespace android
 
 #endif // _LIBS_UTILS_MISC_H
diff --git a/libs/utils/Trace.cpp b/libs/utils/Trace.cpp
index f3ec485..5cd5731 100644
--- a/libs/utils/Trace.cpp
+++ b/libs/utils/Trace.cpp
@@ -19,6 +19,7 @@
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
+#include <utils/misc.h>
 
 namespace android {
 
@@ -27,10 +28,19 @@
 uint64_t Tracer::sEnabledTags = 0;
 Mutex Tracer::sMutex;
 
+void Tracer::changeCallback() {
+    Mutex::Autolock lock(sMutex);
+    if (sIsReady && sTraceFD >= 0) {
+        loadSystemProperty();
+    }
+}
+
 void Tracer::init() {
     Mutex::Autolock lock(sMutex);
 
     if (!sIsReady) {
+        add_sysprop_change_callback(changeCallback, 0);
+
         const char* const traceFileName =
                 "/sys/kernel/debug/tracing/trace_marker";
         sTraceFD = open(traceFileName, O_WRONLY);
@@ -38,14 +48,18 @@
             ALOGE("error opening trace file: %s (%d)", strerror(errno), errno);
             // sEnabledTags remains zero indicating that no tracing can occur
         } else {
-            char value[PROPERTY_VALUE_MAX];
-            property_get("debug.atrace.tags.enableflags", value, "0");
-            sEnabledTags = (strtoll(value, NULL, 0) & ATRACE_TAG_VALID_MASK)
-                    | ATRACE_TAG_ALWAYS;
+            loadSystemProperty();
         }
 
         android_atomic_release_store(1, &sIsReady);
     }
 }
 
+void Tracer::loadSystemProperty() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.atrace.tags.enableflags", value, "0");
+    sEnabledTags = (strtoll(value, NULL, 0) & ATRACE_TAG_VALID_MASK)
+            | ATRACE_TAG_ALWAYS;
+}
+
 } // namespace andoid
diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp
index dc89d15..b3c99e6 100644
--- a/libs/utils/misc.cpp
+++ b/libs/utils/misc.cpp
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "misc"
+
 //
 // Miscellaneous utility functions.
 //
 #include <utils/misc.h>
+#include <utils/Log.h>
 
 #include <sys/stat.h>
 #include <string.h>
@@ -25,6 +28,12 @@
 #include <assert.h>
 #include <stdio.h>
 
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/Vector.h>
+
 using namespace android;
 
 namespace android {
@@ -181,5 +190,54 @@
     return val;
 }
 
-}; // namespace android
+struct sysprop_change_callback_info {
+    sysprop_change_callback callback;
+    int priority;
+};
 
+#if defined(HAVE_PTHREADS)
+static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
+static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
+#endif
+
+void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
+#if defined(HAVE_PTHREADS)
+    pthread_mutex_lock(&gSyspropMutex);
+    if (gSyspropList == NULL) {
+        gSyspropList = new Vector<sysprop_change_callback_info>();
+    }
+    sysprop_change_callback_info info;
+    info.callback = cb;
+    info.priority = priority;
+    bool added = false;
+    for (size_t i=0; i<gSyspropList->size(); i++) {
+        if (priority >= gSyspropList->itemAt(i).priority) {
+            gSyspropList->insertAt(info, i);
+            added = true;
+            break;
+        }
+    }
+    if (!added) {
+        gSyspropList->add(info);
+    }
+    pthread_mutex_unlock(&gSyspropMutex);
+#endif
+}
+
+void report_sysprop_change() {
+#if defined(HAVE_PTHREADS)
+    pthread_mutex_lock(&gSyspropMutex);
+    Vector<sysprop_change_callback_info> listeners;
+    if (gSyspropList != NULL) {
+        listeners = *gSyspropList;
+    }
+    pthread_mutex_unlock(&gSyspropMutex);
+
+    //ALOGI("Reporting sysprop change to %d listeners", listeners.size());
+    for (size_t i=0; i<listeners.size(); i++) {
+        listeners[i].callback();
+    }
+#endif
+}
+
+}; // namespace android