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

Use this to reload the trace and layout bounds properties.

This is ONLY for debugging.

Change-Id: I1c4bdb52c823520c352c5bac45fa9ee31160793c
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 0586d9e..b7bc45f 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -140,6 +140,9 @@
      */
     int LIKE_TRANSACTION   = ('_'<<24)|('L'<<16)|('I'<<8)|'K';
 
+    /** @hide */
+    int SYSPROPS_TRANSACTION = ('_'<<24)|('S'<<16)|('P'<<8)|'R';
+
     /**
      * Flag to {@link #transact}: this is a one-way call, meaning that the
      * caller returns immediately, without waiting for a result from the
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 43b5128..be24426 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import java.util.ArrayList;
+
 
 /**
  * Native implementation of the service manager.  Most clients will only
@@ -151,14 +153,32 @@
     }
     
     public String[] listServices() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IServiceManager.descriptor);
-        mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
-        String[] list = reply.readStringArray();
-        reply.recycle();
-        data.recycle();
-        return list;
+        ArrayList<String> services = new ArrayList<String>();
+        int n = 0;
+        while (true) {
+            Parcel data = Parcel.obtain();
+            Parcel reply = Parcel.obtain();
+            data.writeInterfaceToken(IServiceManager.descriptor);
+            data.writeInt(n);
+            n++;
+            try {
+                boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
+                if (!res) {
+                    break;
+                }
+            } catch (RuntimeException e) {
+                // The result code that is returned by the C++ code can
+                // cause the call to throw an exception back instead of
+                // returning a nice result...  so eat it here and go on.
+                break;
+            }
+            services.add(reply.readString());
+            reply.recycle();
+            data.recycle();
+        }
+        String[] array = new String[services.size()];
+        services.toArray(array);
+        return array;
     }
 
     public void setPermissionController(IPermissionController controller)
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 619bf8d..156600e 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -16,6 +16,10 @@
 
 package android.os;
 
+import java.util.ArrayList;
+
+import android.util.Log;
+
 
 /**
  * Gives access to the system properties store.  The system properties
@@ -28,12 +32,15 @@
     public static final int PROP_NAME_MAX = 31;
     public static final int PROP_VALUE_MAX = 91;
 
+    private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
+
     private static native String native_get(String key);
     private static native String native_get(String key, String def);
     private static native int native_get_int(String key, int def);
     private static native long native_get_long(String key, long def);
     private static native boolean native_get_boolean(String key, boolean def);
     private static native void native_set(String key, String def);
+    private static native void native_add_change_callback();
 
     /**
      * Get the value for the given key.
@@ -124,4 +131,26 @@
         }
         native_set(key, val);
     }
+
+    public static void addChangeCallback(Runnable callback) {
+        synchronized (sChangeCallbacks) {
+            if (sChangeCallbacks.size() == 0) {
+                native_add_change_callback();
+            }
+            sChangeCallbacks.add(callback);
+        }
+    }
+
+    static void callChangeCallbacks() {
+        synchronized (sChangeCallbacks) {
+            //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
+            if (sChangeCallbacks.size() == 0) {
+                return;
+            }
+            ArrayList<Runnable> callbacks = new ArrayList<Runnable>(sChangeCallbacks);
+            for (int i=0; i<callbacks.size(); i++) {
+                callbacks.get(i).run();
+            }
+        }
+    }
 }
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 7b6fd64..911183d 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -47,13 +47,21 @@
 
     public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags";
 
-    private static final long sEnabledTags = nativeGetEnabledTags();
+    private static long sEnabledTags = nativeGetEnabledTags();
 
     private static native long nativeGetEnabledTags();
     private static native void nativeTraceCounter(long tag, String name, int value);
     private static native void nativeTraceBegin(long tag, String name);
     private static native void nativeTraceEnd(long tag);
 
+    static {
+        SystemProperties.addChangeCallback(new Runnable() {
+            @Override public void run() {
+                sEnabledTags = nativeGetEnabledTags();
+            }
+        });
+    }
+
     private Trace() {
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9fa67ac..aad6756 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17250,7 +17250,7 @@
         /**
          * Show where the margins, bounds and layout bounds are for each view.
          */
-        final boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
+        boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
 
         /**
          * Point used to compute visible regions.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5f295cb..6e6fab2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -408,6 +408,7 @@
 
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mAttachInfo.mScreenOn = powerManager.isScreenOn();
+        loadSystemProperties();
     }
 
     /**
@@ -846,6 +847,16 @@
         scheduleTraversals();
     }
 
+    void invalidateWorld(View view) {
+        view.invalidate();
+        if (view instanceof ViewGroup) {
+            ViewGroup parent = (ViewGroup)view;
+            for (int i=0; i<parent.getChildCount(); i++) {
+                invalidateWorld(parent.getChildAt(i));
+            }
+        }
+    }
+
     public void invalidateChild(View child, Rect dirty) {
         invalidateChildInParent(null, dirty);
     }
@@ -2730,6 +2741,7 @@
     private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
     private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
     private final static int MSG_DISPATCH_DONE_ANIMATING = 23;
+    private final static int MSG_INVALIDATE_WORLD = 24;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -2997,6 +3009,9 @@
             case MSG_DISPATCH_DONE_ANIMATING: {
                 handleDispatchDoneAnimating();
             } break;
+            case MSG_INVALIDATE_WORLD: {
+                invalidateWorld(mView);
+            } break;
             }
         }
     }
@@ -4016,6 +4031,17 @@
         mHandler.sendMessage(msg);
     }
 
+    public void loadSystemProperties() {
+        boolean layout = SystemProperties.getBoolean(
+                View.DEBUG_LAYOUT_PROPERTY, false);
+        if (layout != mAttachInfo.mDebugLayout) {
+            mAttachInfo.mDebugLayout = layout;
+            if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
+                mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
+            }
+        }
+    }
+
     private void destroyHardwareRenderer() {
         AttachInfo attachInfo = mAttachInfo;
         HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b5690e9..5d33cec 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -23,6 +23,7 @@
 import android.graphics.PixelFormat;
 import android.opengl.ManagedEGLContext;
 import android.os.IBinder;
+import android.os.SystemProperties;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
@@ -112,6 +113,8 @@
     private WindowManager.LayoutParams[] mParams;
     private boolean mNeedsEglTerminate;
 
+    private Runnable mSystemPropertyUpdater = null;
+
     private final static Object sLock = new Object();
     private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
     private final static HashMap<CompatibilityInfo, WindowManager> sCompatWindowManagers
@@ -237,6 +240,22 @@
         View panelParentView = null;
         
         synchronized (this) {
+            // Start watching for system property changes.
+            if (mSystemPropertyUpdater == null) {
+                mSystemPropertyUpdater = new Runnable() {
+                    @Override public void run() {
+                        synchronized (this) {
+                            synchronized (this) {
+                                for (ViewRootImpl root : mRoots) {
+                                    root.loadSystemProperties();
+                                }
+                            }
+                        }
+                    }
+                };
+                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
+            }
+
             // Here's an odd/questionable case: if someone tries to add a
             // view multiple times, then we simply bump up a nesting count
             // and they need to remove the view the corresponding number of
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index add616e..677396d1 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -15,7 +15,11 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "SysPropJNI"
+
 #include "cutils/properties.h"
+#include "utils/misc.h"
+#include <utils/Log.h>
 #include "jni.h"
 #include "android_runtime/AndroidRuntime.h"
 #include <nativehelper/JNIHelp.h>
@@ -188,6 +192,34 @@
     }
 }
 
+static JavaVM* sVM = NULL;
+static jclass sClazz = NULL;
+static jmethodID sCallChangeCallbacks;
+
+static void do_report_sysprop_change() {
+    //ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz);
+    if (sVM != NULL && sClazz != NULL) {
+        JNIEnv* env;
+        if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) {
+            //ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks);
+            env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks);
+        }
+    }
+}
+
+static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
+{
+    // This is called with the Java lock held.
+    if (sVM == NULL) {
+        env->GetJavaVM(&sVM);
+    }
+    if (sClazz == NULL) {
+        sClazz = (jclass) env->NewGlobalRef(clazz);
+        sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
+        add_sysprop_change_callback(do_report_sysprop_change, -10000);
+    }
+}
+
 static JNINativeMethod method_table[] = {
     { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
       (void*) SystemProperties_getS },
@@ -201,6 +233,8 @@
       (void*) SystemProperties_get_boolean },
     { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
       (void*) SystemProperties_set },
+    { "native_add_change_callback", "()V",
+      (void*) SystemProperties_add_change_callback },
 };
 
 int register_android_os_SystemProperties(JNIEnv *env)
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 0f99fb2..04dc49f 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -308,6 +308,12 @@
             env->DeleteLocalRef(excep2);
         }
 
+        // Need to always call through the native implementation of
+        // SYSPROPS_TRANSACTION.
+        if (code == SYSPROPS_TRANSACTION) {
+            BBinder::onTransact(code, data, reply, flags);
+        }
+
         //aout << "onTransact to Java code; result=" << res << endl
         //    << "Transact from " << this << " to Java code returning "
         //    << reply << ": " << *reply << endl;