Merge "Fix a race in BufferQueue"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 7710c5b..b8f505e 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -33,7 +33,7 @@
 #include "private/android_filesystem_config.h"
 
 #define LOG_TAG "dumpstate"
-#include <utils/Log.h>
+#include <cutils/log.h>
 
 #include "dumpstate.h"
 
diff --git a/data/etc/android.hardware.nfc.hce.xml b/data/etc/android.hardware.nfc.hce.xml
new file mode 100644
index 0000000..10b96b1
--- /dev/null
+++ b/data/etc/android.hardware.nfc.hce.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports host-based
+     NFC card emulation -->
+<permissions>
+    <feature name="android.hardware.nfc.hce" />
+</permissions>
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
new file mode 100644
index 0000000..855262b
--- /dev/null
+++ b/include/batteryservice/BatteryService.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BATTERYSERVICE_H
+#define ANDROID_BATTERYSERVICE_H
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// must be kept in sync with definitions in BatteryManager.java
+enum {
+    BATTERY_STATUS_UNKNOWN = 1, // equals BatteryManager.BATTERY_STATUS_UNKNOWN constant
+    BATTERY_STATUS_CHARGING = 2, // equals BatteryManager.BATTERY_STATUS_CHARGING constant
+    BATTERY_STATUS_DISCHARGING = 3, // equals BatteryManager.BATTERY_STATUS_DISCHARGING constant
+    BATTERY_STATUS_NOT_CHARGING = 4, // equals BatteryManager.BATTERY_STATUS_NOT_CHARGING constant
+    BATTERY_STATUS_FULL = 5, // equals BatteryManager.BATTERY_STATUS_FULL constant
+};
+
+// must be kept in sync with definitions in BatteryManager.java
+enum {
+    BATTERY_HEALTH_UNKNOWN = 1, // equals BatteryManager.BATTERY_HEALTH_UNKNOWN constant
+    BATTERY_HEALTH_GOOD = 2, // equals BatteryManager.BATTERY_HEALTH_GOOD constant
+    BATTERY_HEALTH_OVERHEAT = 3, // equals BatteryManager.BATTERY_HEALTH_OVERHEAT constant
+    BATTERY_HEALTH_DEAD = 4, // equals BatteryManager.BATTERY_HEALTH_DEAD constant
+    BATTERY_HEALTH_OVER_VOLTAGE = 5, // equals BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE constant
+    BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6, // equals BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE constant
+    BATTERY_HEALTH_COLD = 7, // equals BatteryManager.BATTERY_HEALTH_COLD constant
+};
+
+struct BatteryProperties {
+    bool chargerAcOnline;
+    bool chargerUsbOnline;
+    bool chargerWirelessOnline;
+    int batteryStatus;
+    int batteryHealth;
+    bool batteryPresent;
+    int batteryLevel;
+    int batteryVoltage;
+    int batteryTemperature;
+    String8 batteryTechnology;
+
+    status_t writeToParcel(Parcel* parcel) const;
+    status_t readFromParcel(Parcel* parcel);
+};
+
+}; // namespace android
+
+#endif // ANDROID_BATTERYSERVICE_H
diff --git a/include/batteryservice/IBatteryPropertiesListener.h b/include/batteryservice/IBatteryPropertiesListener.h
new file mode 100644
index 0000000..b02d8e9
--- /dev/null
+++ b/include/batteryservice/IBatteryPropertiesListener.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IBATTERYPROPERTIESLISTENER_H
+#define ANDROID_IBATTERYPROPERTIESLISTENER_H
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+#include <batteryservice/BatteryService.h>
+
+namespace android {
+
+// must be kept in sync with interface defined in IBatteryPropertiesListener.aidl
+enum {
+        TRANSACT_BATTERYPROPERTIESCHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+// ----------------------------------------------------------------------------
+
+class IBatteryPropertiesListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(BatteryPropertiesListener);
+
+    virtual void batteryPropertiesChanged(struct BatteryProperties props) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IBATTERYPROPERTIESLISTENER_H
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/include/batteryservice/IBatteryPropertiesRegistrar.h
new file mode 100644
index 0000000..8d28b1d
--- /dev/null
+++ b/include/batteryservice/IBatteryPropertiesRegistrar.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IBATTERYPROPERTIESREGISTRAR_H
+#define ANDROID_IBATTERYPROPERTIESREGISTRAR_H
+
+#include <binder/IInterface.h>
+#include <batteryservice/IBatteryPropertiesListener.h>
+
+namespace android {
+
+// must be kept in sync with interface defined in IBatteryPropertiesRegistrar.aidl
+enum {
+    REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
+    UNREGISTER_LISTENER,
+};
+
+class IBatteryPropertiesRegistrar : public IInterface {
+public:
+    DECLARE_META_INTERFACE(BatteryPropertiesRegistrar);
+
+    virtual void registerListener(const sp<IBatteryPropertiesListener>& listener) = 0;
+    virtual void unregisterListener(const sp<IBatteryPropertiesListener>& listener) = 0;
+};
+
+class BnBatteryPropertiesRegistrar : public BnInterface<IBatteryPropertiesRegistrar> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IBATTERYPROPERTIESREGISTRAR_H
diff --git a/include/binder/BufferedTextOutput.h b/include/binder/BufferedTextOutput.h
index adf3c32..9a7c43b 100644
--- a/include/binder/BufferedTextOutput.h
+++ b/include/binder/BufferedTextOutput.h
@@ -19,7 +19,7 @@
 
 #include <binder/TextOutput.h>
 #include <utils/threads.h>
-#include <cutils/uio.h>
+#include <sys/uio.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index d8256c1..1419b45 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -67,10 +67,11 @@
         float resolution;
     };
 
-    void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier,
-            const String8& alias, bool isExternal);
+    void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
+            const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal);
 
     inline int32_t getId() const { return mId; }
+    inline int32_t getControllerNumber() const { return mControllerNumber; }
     inline int32_t getGeneration() const { return mGeneration; }
     inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
     inline const String8& getAlias() const { return mAlias; }
@@ -111,6 +112,7 @@
 private:
     int32_t mId;
     int32_t mGeneration;
+    int32_t mControllerNumber;
     InputDeviceIdentifier mIdentifier;
     String8 mAlias;
     bool mIsExternal;
diff --git a/include/utils/BasicHashtable.h b/include/utils/BasicHashtable.h
index 7a6c96c..c235d62 100644
--- a/include/utils/BasicHashtable.h
+++ b/include/utils/BasicHashtable.h
@@ -52,6 +52,7 @@
     BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor,
             size_t minimumInitialCapacity, float loadFactor);
     BasicHashtableImpl(const BasicHashtableImpl& other);
+    virtual ~BasicHashtableImpl();
 
     void dispose();
 
diff --git a/include/utils/ThreadDefs.h b/include/utils/ThreadDefs.h
index a8f8eb3..9711c13 100644
--- a/include/utils/ThreadDefs.h
+++ b/include/utils/ThreadDefs.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <system/graphics.h>
+#include <system/thread_defs.h>
 
 // ---------------------------------------------------------------------------
 // C API
@@ -32,53 +33,6 @@
 
 typedef int (*android_thread_func_t)(void*);
 
-enum {
-    /*
-     * ***********************************************
-     * ** Keep in sync with android.os.Process.java **
-     * ***********************************************
-     * 
-     * This maps directly to the "nice" priorities we use in Android.
-     * A thread priority should be chosen inverse-proportionally to
-     * the amount of work the thread is expected to do. The more work
-     * a thread will do, the less favorable priority it should get so that 
-     * it doesn't starve the system. Threads not behaving properly might
-     * be "punished" by the kernel.
-     * Use the levels below when appropriate. Intermediate values are
-     * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
-     */
-    ANDROID_PRIORITY_LOWEST         =  19,
-
-    /* use for background tasks */
-    ANDROID_PRIORITY_BACKGROUND     =  10,
-    
-    /* most threads run at normal priority */
-    ANDROID_PRIORITY_NORMAL         =   0,
-    
-    /* threads currently running a UI that the user is interacting with */
-    ANDROID_PRIORITY_FOREGROUND     =  -2,
-
-    /* the main UI thread has a slightly more favorable priority */
-    ANDROID_PRIORITY_DISPLAY        =  -4,
-    
-    /* ui service treads might want to run at a urgent display (uncommon) */
-    ANDROID_PRIORITY_URGENT_DISPLAY =  HAL_PRIORITY_URGENT_DISPLAY,
-    
-    /* all normal audio threads */
-    ANDROID_PRIORITY_AUDIO          = -16,
-    
-    /* service audio threads (uncommon) */
-    ANDROID_PRIORITY_URGENT_AUDIO   = -19,
-
-    /* should never be used in practice. regular process might not 
-     * be allowed to use this level */
-    ANDROID_PRIORITY_HIGHEST        = -20,
-
-    ANDROID_PRIORITY_DEFAULT        = ANDROID_PRIORITY_NORMAL,
-    ANDROID_PRIORITY_MORE_FAVORABLE = -1,
-    ANDROID_PRIORITY_LESS_FAVORABLE = +1,
-};
-
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 4c8820e..f3f8daf 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -47,5 +47,6 @@
 include $(CLEAR_VARS)
 LOCAL_LDLIBS += -lpthread
 LOCAL_MODULE := libbinder
+LOCAL_STATIC_LIBRARIES += libutils
 LOCAL_SRC_FILES := $(sources)
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 99c2747..61b4f7d 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -31,6 +31,7 @@
     if (gToken == NULL) {
         gToken = service->getToken(new BBinder());
     }
+    pthread_mutex_unlock(&gTokenMutex);
     return gToken;
 }
 
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 1750640..a341ca8 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -37,9 +37,11 @@
     
     {
         AutoMutex _l(gDefaultServiceManagerLock);
-        if (gDefaultServiceManager == NULL) {
+        while (gDefaultServiceManager == NULL) {
             gDefaultServiceManager = interface_cast<IServiceManager>(
                 ProcessState::self()->getContextObject(NULL));
+            if (gDefaultServiceManager == NULL)
+                sleep(1);
         }
     }
     
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 294e1d4..c1e49bc 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -194,6 +194,33 @@
         // in getWeakProxyForHandle() for more info about this.
         IBinder* b = e->binder;
         if (b == NULL || !e->refs->attemptIncWeak(this)) {
+            if (handle == 0) {
+                // Special case for context manager...
+                // The context manager is the only object for which we create
+                // a BpBinder proxy without already holding a reference.
+                // Perform a dummy transaction to ensure the context manager
+                // is registered before we create the first local reference
+                // to it (which will occur when creating the BpBinder).
+                // If a local reference is created for the BpBinder when the
+                // context manager is not present, the driver will fail to
+                // provide a reference to the context manager, but the
+                // driver API does not return status.
+                //
+                // Note that this is not race-free if the context manager
+                // dies while this code runs.
+                //
+                // TODO: add a driver API to wait for context manager, or
+                // stop special casing handle 0 for context manager and add
+                // a driver API to get a handle to the context manager with
+                // proper reference counting.
+
+                Parcel data;
+                status_t status = IPCThreadState::self()->transact(
+                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
+                if (status == DEAD_OBJECT)
+                   return NULL;
+            }
+
             b = new BpBinder(handle); 
             e->binder = b;
             if (b) e->refs = b->getWeakRefs();
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 320f4cf..95ba095 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -853,13 +853,13 @@
     if (presentWhen != 0 && desiredPresent > presentWhen &&
             desiredPresent - presentWhen < MAX_FUTURE_NSEC)
     {
-        ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld",
+        ST_LOGV("pts defer: des=%lld when=%lld (%lld) now=%lld",
                 desiredPresent, presentWhen, desiredPresent - presentWhen,
                 systemTime(CLOCK_MONOTONIC));
         return PRESENT_LATER;
     }
     if (presentWhen != 0) {
-        ALOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)",
+        ST_LOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)",
                 mSlots, buf, mSlots[buf].mFence->getSignalTime(),
                 desiredPresent, presentWhen, desiredPresent - presentWhen);
     }
@@ -899,35 +899,31 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(buf);
 
-    Mutex::Autolock _l(mMutex);
-
     if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
         return BAD_VALUE;
     }
 
-    // Check if this buffer slot is on the queue
-    bool slotQueued = false;
-    Fifo::iterator front(mQueue.begin());
-    while (front != mQueue.end() && !slotQueued) {
-        if (front->mBuf == buf)
-            slotQueued = true;
-        front++;
-    }
+    Mutex::Autolock _l(mMutex);
 
     // If the frame number has changed because buffer has been reallocated,
     // we can ignore this releaseBuffer for the old buffer.
     if (frameNumber != mSlots[buf].mFrameNumber) {
-        // This should only occur if new buffer is still in the queue
-        ALOGE_IF(!slotQueued,
-                "received old buffer(#%lld) after new buffer(#%lld) on same "
-                "slot #%d already acquired", frameNumber,
-                mSlots[buf].mFrameNumber, buf);
         return STALE_BUFFER_SLOT;
     }
-    // this should never happen
-    ALOGE_IF(slotQueued,
-            "received new buffer(#%lld) on slot #%d that has not yet been "
-            "acquired", frameNumber, buf);
+
+
+    // Internal state consistency checks:
+    // Make sure this buffers hasn't been queued while we were owning it (acquired)
+    Fifo::iterator front(mQueue.begin());
+    Fifo::const_iterator const end(mQueue.end());
+    while (front != end) {
+        if (front->mBuf == buf) {
+            LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been "
+                    "acquired", mConsumerName.string(), frameNumber, buf);
+            break; // never reached
+        }
+        front++;
+    }
 
     // The buffer can now only be released if its in the acquired state
     if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
@@ -1017,8 +1013,7 @@
     return NO_ERROR;
 }
 
-status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
-{
+status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
     ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
     if (!w || !h) {
         ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 54703d4..b11110a 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -127,26 +127,25 @@
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
-    initialize(-1, -1, InputDeviceIdentifier(), String8(), false);
+    initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false);
 }
 
 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
-        mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier),
-        mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources),
-        mKeyboardType(other.mKeyboardType),
-        mKeyCharacterMap(other.mKeyCharacterMap),
-        mHasVibrator(other.mHasVibrator),
-        mHasButtonUnderPad(other.mHasButtonUnderPad),
-        mMotionRanges(other.mMotionRanges) {
+        mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber),
+        mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal),
+        mSources(other.mSources), mKeyboardType(other.mKeyboardType),
+        mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator),
+        mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) {
 }
 
 InputDeviceInfo::~InputDeviceInfo() {
 }
 
-void InputDeviceInfo::initialize(int32_t id, int32_t generation,
+void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
         const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
     mId = id;
     mGeneration = generation;
+    mControllerNumber = controllerNumber;
     mIdentifier = identifier;
     mAlias = alias;
     mIsExternal = isExternal;
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 42e1c7e..abf4b2e 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -66,6 +66,7 @@
 LOCAL_SRC_FILES += Looper.cpp
 endif
 LOCAL_MODULE:= libutils
+LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(host_commonCflags)
 LOCAL_LDLIBS += $(host_commonLdlibs)
 include $(BUILD_HOST_STATIC_LIBRARY)
@@ -79,6 +80,7 @@
 LOCAL_SRC_FILES += Looper.cpp
 endif
 LOCAL_MODULE:= lib64utils
+LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(host_commonCflags) -m64
 LOCAL_LDLIBS += $(host_commonLdlibs)
 include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libs/utils/BasicHashtable.cpp b/libs/utils/BasicHashtable.cpp
index fd51b7b..491d9e9 100644
--- a/libs/utils/BasicHashtable.cpp
+++ b/libs/utils/BasicHashtable.cpp
@@ -42,6 +42,10 @@
     }
 }
 
+BasicHashtableImpl::~BasicHashtableImpl()
+{
+}
+
 void BasicHashtableImpl::dispose() {
     if (mBuckets) {
         releaseBuckets(mBuckets, mBucketCount);
diff --git a/libs/utils/CleanSpec.mk b/libs/utils/CleanSpec.mk
new file mode 100644
index 0000000..c3c5651
--- /dev/null
+++ b/libs/utils/CleanSpec.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libutils_intermediates/import_includes)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/lib64utils_intermediates/import_includes)
diff --git a/services/batteryservice/Android.mk b/services/batteryservice/Android.mk
new file mode 100644
index 0000000..0a29c36
--- /dev/null
+++ b/services/batteryservice/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	BatteryProperties.cpp \
+	IBatteryPropertiesListener.cpp \
+	IBatteryPropertiesRegistrar.cpp
+
+LOCAL_STATIC_LIBRARIES := \
+	libutils \
+	libbinder
+
+LOCAL_MODULE:= libbatteryservice
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/services/batteryservice/BatteryProperties.cpp b/services/batteryservice/BatteryProperties.cpp
new file mode 100644
index 0000000..ab636a9
--- /dev/null
+++ b/services/batteryservice/BatteryProperties.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <batteryservice/BatteryService.h>
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+namespace android {
+
+/*
+ * Parcel read/write code must be kept in sync with
+ * frameworks/base/core/java/android/os/BatteryProperties.java
+ */
+
+status_t BatteryProperties::readFromParcel(Parcel* p) {
+    chargerAcOnline = p->readInt32() == 1 ? true : false;
+    chargerUsbOnline = p->readInt32() == 1 ? true : false;
+    chargerWirelessOnline = p->readInt32() == 1 ? true : false;
+    batteryStatus = p->readInt32();
+    batteryHealth = p->readInt32();
+    batteryPresent = p->readInt32() == 1 ? true : false;
+    batteryLevel = p->readInt32();
+    batteryVoltage = p->readInt32();
+    batteryTemperature = p->readInt32();
+    batteryTechnology = String8((p->readString16()).string());
+    return OK;
+}
+
+status_t BatteryProperties::writeToParcel(Parcel* p) const {
+    p->writeInt32(chargerAcOnline ? 1 : 0);
+    p->writeInt32(chargerUsbOnline ? 1 : 0);
+    p->writeInt32(chargerWirelessOnline ? 1 : 0);
+    p->writeInt32(batteryStatus);
+    p->writeInt32(batteryHealth);
+    p->writeInt32(batteryPresent ? 1 : 0);
+    p->writeInt32(batteryLevel);
+    p->writeInt32(batteryVoltage);
+    p->writeInt32(batteryTemperature);
+    p->writeString16(String16(batteryTechnology));
+    return OK;
+}
+
+}; // namespace android
diff --git a/services/batteryservice/IBatteryPropertiesListener.cpp b/services/batteryservice/IBatteryPropertiesListener.cpp
new file mode 100644
index 0000000..19ac7f0
--- /dev/null
+++ b/services/batteryservice/IBatteryPropertiesListener.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <batteryservice/IBatteryPropertiesListener.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class BpBatteryPropertiesListener : public BpInterface<IBatteryPropertiesListener>
+{
+public:
+    BpBatteryPropertiesListener(const sp<IBinder>& impl)
+        : BpInterface<IBatteryPropertiesListener>(impl)
+    {
+    }
+
+    void batteryPropertiesChanged(struct BatteryProperties props)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor());
+        data.writeInt32(1);
+        props.writeToParcel(&data);
+        status_t err = remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(BatteryPropertiesListener, "android.os.IBatteryPropertiesListener");
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
new file mode 100644
index 0000000..6c2d2a5
--- /dev/null
+++ b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IBatteryPropertiesRegistrar"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <batteryservice/IBatteryPropertiesListener.h>
+#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class BpBatteryPropertiesRegistrar : public BpInterface<IBatteryPropertiesRegistrar> {
+public:
+    BpBatteryPropertiesRegistrar(const sp<IBinder>& impl)
+        : BpInterface<IBatteryPropertiesRegistrar>(impl) {}
+
+        void registerListener(const sp<IBatteryPropertiesListener>& listener) {
+            Parcel data;
+            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
+            data.writeStrongBinder(listener->asBinder());
+            remote()->transact(REGISTER_LISTENER, data, NULL);
+        }
+
+        void unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
+            Parcel data;
+            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
+            data.writeStrongBinder(listener->asBinder());
+            remote()->transact(UNREGISTER_LISTENER, data, NULL);
+        }
+};
+
+IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");
+
+status_t BnBatteryPropertiesRegistrar::onTransact(uint32_t code,
+                                                  const Parcel& data,
+                                                  Parcel* reply,
+                                                  uint32_t flags)
+{
+    switch(code) {
+        case REGISTER_LISTENER: {
+            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
+            sp<IBatteryPropertiesListener> listener =
+                interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
+            registerListener(listener);
+            return OK;
+        }
+
+        case UNREGISTER_LISTENER: {
+            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
+            sp<IBatteryPropertiesListener> listener =
+                interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
+            unregisterListener(listener);
+            return OK;
+        }
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/connectivitymanager/Android.mk b/services/connectivitymanager/Android.mk
new file mode 100644
index 0000000..e986abc
--- /dev/null
+++ b/services/connectivitymanager/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= ConnectivityManager.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+	libbinder
+
+LOCAL_MODULE:= libconnectivitymanager
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/connectivitymanager/ConnectivityManager.cpp b/services/connectivitymanager/ConnectivityManager.cpp
new file mode 100644
index 0000000..949c2ac
--- /dev/null
+++ b/services/connectivitymanager/ConnectivityManager.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+
+#include <utils/Singleton.h>
+
+#include <binder/BinderService.h>
+#include <binder/Parcel.h>
+
+#include "ConnectivityManager.h"
+
+namespace android {
+
+ConnectivityManager::ConnectivityManager() {
+    const sp<IServiceManager> sm(defaultServiceManager());
+    if (sm != NULL) {
+        const String16 name("connectivity");
+        mConnectivityService = sm->getService(name);
+    }
+}
+
+void ConnectivityManager::markSocketAsUserImpl(int fd, uid_t uid) {
+    Parcel data, reply;
+    data.writeInterfaceToken(DESCRIPTOR);
+    // parcelable objects are preceded by a 1 if not null in aidl generated code.
+    // Play nice with the generated Java
+    data.writeInt32(1);
+    data.writeFileDescriptor(fd);
+    data.writeInt32(uid);
+    mConnectivityService->transact(TRANSACTION_markSocketAsUser, data, &reply, 0);
+}
+
+const String16 ConnectivityManager::DESCRIPTOR("android.net.IConnectivityManager");
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ConnectivityManager)
+
+};
diff --git a/services/connectivitymanager/ConnectivityManager.h b/services/connectivitymanager/ConnectivityManager.h
new file mode 100644
index 0000000..37f5d98
--- /dev/null
+++ b/services/connectivitymanager/ConnectivityManager.h
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Singleton.h>
+
+namespace android {
+
+class ConnectivityManager : public Singleton<ConnectivityManager> {
+    // Keep this in sync with IConnectivityManager.aidl
+    static const int TRANSACTION_markSocketAsUser = IBinder::FIRST_CALL_TRANSACTION;
+    static const String16 DESCRIPTOR;
+
+    friend class Singleton<ConnectivityManager>;
+    sp<IBinder> mConnectivityService;
+
+    ConnectivityManager();
+
+    void markSocketAsUserImpl(int fd, uid_t uid);
+
+public:
+    static void markSocketAsUser(int fd, uid_t uid) {
+        ConnectivityManager::getInstance().markSocketAsUserImpl(fd, uid);
+    }
+};
+
+};
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
index 815242b..47bab83 100644
--- a/services/surfaceflinger/EventLog/EventLog.cpp
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -31,17 +31,22 @@
 EventLog::EventLog() {
 }
 
-void EventLog::doLogJank(const String8& window, int32_t value) {
-    EventLog::TagBuffer buffer(LOGTAG_SF_JANK);
-    buffer.startList(2);
+void EventLog::doLogFrameDurations(const String8& window,
+        const int32_t* durations, size_t numDurations) {
+    EventLog::TagBuffer buffer(LOGTAG_SF_FRAME_DUR);
+    buffer.startList(1 + numDurations);
     buffer.writeString8(window);
-    buffer.writeInt32(value);
+    for (size_t i = 0; i < numDurations; i++) {
+        buffer.writeInt32(durations[i]);
+    }
     buffer.endList();
     buffer.log();
 }
 
-void EventLog::logJank(const String8& window, int32_t value) {
-    EventLog::getInstance().doLogJank(window, value);
+void EventLog::logFrameDurations(const String8& window,
+        const int32_t* durations, size_t numDurations) {
+    EventLog::getInstance().doLogFrameDurations(window, durations,
+            numDurations);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h
index 2f1cd9b..5207514 100644
--- a/services/surfaceflinger/EventLog/EventLog.h
+++ b/services/surfaceflinger/EventLog/EventLog.h
@@ -30,7 +30,8 @@
 class EventLog : public Singleton<EventLog> {
 
 public:
-    static void logJank(const String8& window, int32_t value);
+    static void logFrameDurations(const String8& window,
+            const int32_t* durations, size_t numDurations);
 
 protected:
     EventLog();
@@ -72,8 +73,9 @@
     EventLog(const EventLog&);
     EventLog& operator =(const EventLog&);
 
-    enum { LOGTAG_SF_JANK = 60100 };
-    void doLogJank(const String8& window, int32_t value);
+    enum { LOGTAG_SF_FRAME_DUR = 60100 };
+    void doLogFrameDurations(const String8& window, const int32_t* durations,
+            size_t numDurations);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags
index c83692f..791e0e4 100644
--- a/services/surfaceflinger/EventLog/EventLogTags.logtags
+++ b/services/surfaceflinger/EventLog/EventLogTags.logtags
@@ -30,9 +30,12 @@
 # 5: Id
 # 6: Percent
 # Default value for data of type int/long is 2 (bytes).
+#
+# See system/core/logcat/event.logtags for the master copy of the tags.
 
-# surfaceflinger
-60100 sf_jank (window|3),(value|1)
+# 60100 - 60199 reserved for surfaceflinger
+
+60100 sf_frame_dur (window|3),(dur0|1),(dur1|1),(dur2|1),(dur3|1),(dur4|1),(dur5|1),(dur6|1)
 
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 9b55d44..d406672 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -17,17 +17,22 @@
 // This is needed for stdint.h to define INT64_MAX in C++
 #define __STDC_LIMIT_MACROS
 
+#include <cutils/log.h>
+
 #include <ui/Fence.h>
 
 #include <utils/String8.h>
 
 #include "FrameTracker.h"
+#include "EventLog/EventLog.h"
 
 namespace android {
 
 FrameTracker::FrameTracker() :
         mOffset(0),
-        mNumFences(0) {
+        mNumFences(0),
+        mDisplayPeriod(0) {
+    resetFrameCountersLocked();
 }
 
 void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
@@ -57,8 +62,18 @@
     mNumFences++;
 }
 
+void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
+    Mutex::Autolock lock(mMutex);
+    mDisplayPeriod = displayPeriod;
+}
+
 void FrameTracker::advanceFrame() {
     Mutex::Autolock lock(mMutex);
+
+    // Update the statistic to include the frame we just finished.
+    updateStatsLocked(mOffset);
+
+    // Advance to the next frame.
     mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
     mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
     mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
@@ -98,12 +113,19 @@
     mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
 }
 
+void FrameTracker::logAndResetStats(const String8& name) {
+    Mutex::Autolock lock(mMutex);
+    logStatsLocked(name);
+    resetFrameCountersLocked();
+}
+
 void FrameTracker::processFencesLocked() const {
     FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
     int& numFences = const_cast<int&>(mNumFences);
 
     for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
         size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS;
+        bool updated = false;
 
         const sp<Fence>& rfence = records[idx].frameReadyFence;
         if (rfence != NULL) {
@@ -111,6 +133,7 @@
             if (records[idx].frameReadyTime < INT64_MAX) {
                 records[idx].frameReadyFence = NULL;
                 numFences--;
+                updated = true;
             }
         }
 
@@ -120,11 +143,67 @@
             if (records[idx].actualPresentTime < INT64_MAX) {
                 records[idx].actualPresentFence = NULL;
                 numFences--;
+                updated = true;
             }
         }
+
+        if (updated) {
+            updateStatsLocked(idx);
+        }
     }
 }
 
+void FrameTracker::updateStatsLocked(size_t newFrameIdx) const {
+    int* numFrames = const_cast<int*>(mNumFrames);
+
+    if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) {
+        size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) %
+                NUM_FRAME_RECORDS;
+
+        if (isFrameValidLocked(prevFrameIdx)) {
+            nsecs_t newPresentTime =
+                    mFrameRecords[newFrameIdx].actualPresentTime;
+            nsecs_t prevPresentTime =
+                    mFrameRecords[prevFrameIdx].actualPresentTime;
+
+            nsecs_t duration = newPresentTime - prevPresentTime;
+            int numPeriods = int((duration + mDisplayPeriod/2) /
+                    mDisplayPeriod);
+
+            for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) {
+                int nextBucket = 1 << (i+1);
+                if (numPeriods < nextBucket) {
+                    numFrames[i]++;
+                    return;
+                }
+            }
+
+            // The last duration bucket is a catch-all.
+            numFrames[NUM_FRAME_BUCKETS-1]++;
+        }
+    }
+}
+
+void FrameTracker::resetFrameCountersLocked() {
+    for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
+        mNumFrames[i] = 0;
+    }
+}
+
+void FrameTracker::logStatsLocked(const String8& name) const {
+    for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
+        if (mNumFrames[i] > 0) {
+            EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
+            return;
+        }
+    }
+}
+
+bool FrameTracker::isFrameValidLocked(size_t idx) const {
+    return mFrameRecords[idx].actualPresentTime > 0 &&
+            mFrameRecords[idx].actualPresentTime < INT64_MAX;
+}
+
 void FrameTracker::dump(String8& result) const {
     Mutex::Autolock lock(mMutex);
     processFencesLocked();
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 3d122c4..9233247 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -43,6 +43,8 @@
     // frame time history.
     enum { NUM_FRAME_RECORDS = 128 };
 
+    enum { NUM_FRAME_BUCKETS = 7 };
+
     FrameTracker();
 
     // setDesiredPresentTime sets the time at which the current frame
@@ -68,12 +70,21 @@
     // at which the current frame became visible to the user.
     void setActualPresentFence(const sp<Fence>& fence);
 
+    // setDisplayRefreshPeriod sets the display refresh period in nanoseconds.
+    // This is used to compute frame presentation duration statistics relative
+    // to this period.
+    void setDisplayRefreshPeriod(nsecs_t displayPeriod);
+
     // advanceFrame advances the frame tracker to the next frame.
     void advanceFrame();
 
     // clear resets all the tracked frame data to zero.
     void clear();
 
+    // logAndResetStats dumps the current statistics to the binary event log
+    // and then resets the accumulated statistics to their initial values.
+    void logAndResetStats(const String8& name);
+
     // dump appends the current frame display time history to the result string.
     void dump(String8& result) const;
 
@@ -99,6 +110,21 @@
     // change.  This allows it to be called from the dump method.
     void processFencesLocked() const;
 
+    // updateStatsLocked updates the running statistics that are gathered
+    // about the frame times.
+    void updateStatsLocked(size_t newFrameIdx) const;
+
+    // resetFrameCounteresLocked sets all elements of the mNumFrames array to
+    // 0.
+    void resetFrameCountersLocked();
+
+    // logStatsLocked dumps the current statistics to the binary event log.
+    void logStatsLocked(const String8& name) const;
+
+    // isFrameValidLocked returns true if the data for the given frame index is
+    // valid and has all arrived (i.e. there are no oustanding fences).
+    bool isFrameValidLocked(size_t idx) const;
+
     // mFrameRecords is the circular buffer storing the tracked data for each
     // frame.
     FrameRecord mFrameRecords[NUM_FRAME_RECORDS];
@@ -115,6 +141,17 @@
     // doesn't grow with NUM_FRAME_RECORDS.
     int mNumFences;
 
+    // mNumFrames keeps a count of the number of frames with a duration in a
+    // particular range of vsync periods.  Element n of the array stores the
+    // number of frames with duration in the half-inclusive range
+    // [2^n, 2^(n+1)).  The last element of the array contains the count for
+    // all frames with duration greater than 2^(NUM_FRAME_BUCKETS-1).
+    int32_t mNumFrames[NUM_FRAME_BUCKETS];
+
+    // mDisplayPeriod is the display refresh period of the display for which
+    // this FrameTracker is gathering information.
+    nsecs_t mDisplayPeriod;
+
     // mMutex is used to protect access to all member variables.
     mutable Mutex mMutex;
 };
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 52211c2..7f2ce2b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -104,6 +104,10 @@
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
+
+    nsecs_t displayPeriod =
+            flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+    mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
 }
 
 void Layer::onFirstRef()
@@ -134,6 +138,7 @@
         c->detachLayer(this);
     }
     mFlinger->deleteTextureAsync(mTextureName);
+    mFrameTracker.logAndResetStats(mName);
 }
 
 // ---------------------------------------------------------------------------
@@ -1179,6 +1184,10 @@
     mFrameTracker.clear();
 }
 
+void Layer::logFrameStats() {
+    mFrameTracker.logAndResetStats(mName);
+}
+
 // ---------------------------------------------------------------------------
 
 Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0ceb15e..9093116 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -298,6 +298,7 @@
     void dump(String8& result, Colorizer& colorizer) const;
     void dumpStats(String8& result) const;
     void clearStats();
+    void logFrameStats();
 
 protected:
     // constant
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9adabe8..cbdcd12 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -964,6 +964,11 @@
 
     mLastSwapBufferTime = systemTime() - now;
     mDebugInSwapBuffers = 0;
+
+    uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
+    if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+        logFrameStats();
+    }
 }
 
 void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
@@ -1972,6 +1977,10 @@
     displays.add(d);
     setTransactionState(state, displays, 0);
     onScreenAcquired(getDefaultDisplayDevice());
+
+    const nsecs_t period =
+            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+    mAnimFrameTracker.setDisplayRefreshPeriod(period);
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -2205,6 +2214,19 @@
     mAnimFrameTracker.clear();
 }
 
+// This should only be called from the main thread.  Otherwise it would need
+// the lock and should use mCurrentState rather than mDrawingState.
+void SurfaceFlinger::logFrameStats() {
+    const LayerVector& drawingLayers = mDrawingState.layersSortedByZ;
+    const size_t count = drawingLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<Layer>& layer(drawingLayers[i]);
+        layer->logFrameStats();
+    }
+
+    mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
+}
+
 /*static*/ void SurfaceFlinger::appendSfConfigString(String8& result)
 {
     static const char* config =
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 21d523b..7099b35 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -132,6 +132,10 @@
     friend class Layer;
     friend class SurfaceTextureLayer;
 
+    // This value is specified in number of frames.  Log frame stats at most
+    // every half hour.
+    enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
+
     // We're reference counted, never destroy SurfaceFlinger directly
     virtual ~SurfaceFlinger();
 
@@ -392,6 +396,8 @@
             const sp<const DisplayDevice>& hw,
             uint32_t minLayerZ, uint32_t maxLayerZ);
 
+    void logFrameStats();
+
     /* ------------------------------------------------------------------------
      * Attributes
      */