Adding render stats APIs to UiAutomation (framework native).

bug:12927198

Change-Id: Ibb1c07f7d89e11281e5c1f27f412a29ac6f9c4ab
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 35dcd4e..efde5db 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -22,9 +22,12 @@
 
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
 
 #include <binder/IInterface.h>
 
+#include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
 
 #include <gui/IGraphicBufferAlloc.h>
@@ -122,6 +125,19 @@
             uint32_t reqWidth, uint32_t reqHeight,
             uint32_t minLayerZ, uint32_t maxLayerZ,
             bool useIdentityTransform) = 0;
+
+
+    /* Clears the frame statistics for animations.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t clearAnimationFrameStats() = 0;
+
+    /* Gets the frame statistics for animations.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -145,6 +161,8 @@
         GET_DISPLAY_INFO,
         CONNECT_DISPLAY,
         CAPTURE_SCREEN,
+        CLEAR_ANIMATION_FRAME_STATS,
+        GET_ANIMATION_FRAME_STATS
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index cb9816f..58c1f6a 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -25,6 +25,7 @@
 
 #include <binder/IInterface.h>
 
+#include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
 
 namespace android {
@@ -65,6 +66,16 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t destroySurface(const sp<IBinder>& handle) = 0;
+
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
+    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
+
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
+    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index ac53f02..6a53ccb 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -28,6 +28,7 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
@@ -125,6 +126,12 @@
     status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
     status_t    destroySurface(const sp<IBinder>& id);
 
+    status_t clearLayerFrameStats(const sp<IBinder>& token) const;
+    status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
+
+    static status_t clearAnimationFrameStats();
+    static status_t getAnimationFrameStats(FrameStats* outStats);
+
     static void setDisplaySurface(const sp<IBinder>& token,
             const sp<IGraphicBufferProducer>& bufferProducer);
     static void setDisplayLayerStack(const sp<IBinder>& token,
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index f27754c..84fb9f9 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -24,6 +24,7 @@
 #include <utils/RefBase.h>
 #include <utils/threads.h>
 
+#include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
 
@@ -52,10 +53,10 @@
 
     static bool isSameSurface(
             const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
-        
+
     // release surface data from java
     void        clear();
-    
+
     status_t    setLayerStack(int32_t layerStack);
     status_t    setLayer(int32_t layer);
     status_t    setPosition(float x, float y);
@@ -73,6 +74,9 @@
 
     sp<Surface> getSurface() const;
 
+    status_t clearLayerFrameStats() const;
+    status_t getLayerFrameStats(FrameStats* outStats) const;
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -90,7 +94,7 @@
 
     status_t validate() const;
     void destroy();
-    
+
     sp<SurfaceComposerClient>   mClient;
     sp<IBinder>                 mHandle;
     sp<IGraphicBufferProducer>  mGraphicBufferProducer;
diff --git a/include/ui/FrameStats.h b/include/ui/FrameStats.h
new file mode 100644
index 0000000..5fdf94d
--- /dev/null
+++ b/include/ui/FrameStats.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 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_UI_FRAME_STATS_H
+#define ANDROID_UI_FRAME_STATS_H
+
+#include <utils/Flattenable.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class FrameStats : public LightFlattenable<FrameStats> {
+public:
+
+    /*
+     * Approximate refresh time, in nanoseconds.
+     */
+    nsecs_t refreshPeriodNano;
+
+   /*
+    * The times in nanoseconds for when the frame contents were posted by the producer (e.g.
+    * the application). They are either explicitly set or defaulted to the time when
+    * Surface::queueBuffer() was called.
+    */
+    Vector<nsecs_t> desiredPresentTimesNano;
+
+   /*
+    * The times in milliseconds for when the frame contents were presented on the screen.
+    */
+    Vector<nsecs_t> actualPresentTimesNano;
+
+   /*
+    * The times in nanoseconds for when the frame contents were ready to be presented. Note that
+    * a frame can be posted and still it contents being rendered asynchronously in GL. In such a
+    * case these are the times when the frame contents were completely rendered (i.e. their fences
+    * signaled).
+    */
+    Vector<nsecs_t> frameReadyTimesNano;
+
+    // LightFlattenable
+    bool isFixedSize() const;
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(void const* buffer, size_t size);
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_FRAME_STATS_H
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index e96cc54..c067244 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -229,6 +229,21 @@
         memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
         return reply.readInt32();
     }
+
+    virtual status_t clearAnimationFrameStats() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t getAnimationFrameStats(FrameStats* outStats) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply);
+        reply.read(*outStats);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -351,6 +366,20 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case CLEAR_ANIMATION_FRAME_STATS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            status_t result = clearAnimationFrameStats();
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
+        case GET_ANIMATION_FRAME_STATS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            FrameStats stats;
+            status_t result = getAnimationFrameStats(&stats);
+            reply->write(stats);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 1adc134..3da6423 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -39,7 +39,9 @@
 
 enum {
     CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
-    DESTROY_SURFACE
+    DESTROY_SURFACE,
+    CLEAR_LAYER_FRAME_STATS,
+    GET_LAYER_FRAME_STATS
 };
 
 class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
@@ -73,6 +75,23 @@
         remote()->transact(DESTROY_SURFACE, data, &reply);
         return reply.readInt32();
     }
+
+    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+        data.writeStrongBinder(handle);
+        remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+        data.writeStrongBinder(handle);
+        remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
+        reply.read(*outStats);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
@@ -101,7 +120,23 @@
         } break;
         case DESTROY_SURFACE: {
             CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            reply->writeInt32( destroySurface( data.readStrongBinder() ) );
+            reply->writeInt32(destroySurface( data.readStrongBinder() ) );
+            return NO_ERROR;
+        } break;
+       case CLEAR_LAYER_FRAME_STATS: {
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+            sp<IBinder> handle = data.readStrongBinder();
+            status_t result = clearLayerFrameStats(handle);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case GET_LAYER_FRAME_STATS: {
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+            sp<IBinder> handle = data.readStrongBinder();
+            FrameStats stats;
+            status_t result = getLayerFrameStats(handle, &stats);
+            reply->write(stats);
+            reply->writeInt32(result);
             return NO_ERROR;
         } break;
         default:
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6b20eaf..b7af415 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -515,6 +515,21 @@
     return err;
 }
 
+status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
+    }
+    return mClient->clearLayerFrameStats(token);
+}
+
+status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token,
+        FrameStats* outStats) const {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
+    }
+    return mClient->getLayerFrameStats(token, outStats);
+}
+
 inline Composer& SurfaceComposerClient::getComposer() {
     return mComposer;
 }
@@ -622,6 +637,14 @@
     ComposerService::getComposerService()->unblank(token);
 }
 
+status_t SurfaceComposerClient::clearAnimationFrameStats() {
+    return ComposerService::getComposerService()->clearAnimationFrameStats();
+}
+
+status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
+    return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
+}
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index de182ee..7c6dfb8 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -156,6 +156,20 @@
     return client->setCrop(mHandle, crop);
 }
 
+status_t SurfaceControl::clearLayerFrameStats() const {
+    status_t err = validate();
+    if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
+    return client->clearLayerFrameStats(mHandle);
+}
+
+status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const {
+    status_t err = validate();
+    if (err < 0) return err;
+    const sp<SurfaceComposerClient>& client(mClient);
+    return client->getLayerFrameStats(mHandle, outStats);
+}
+
 status_t SurfaceControl::validate() const
 {
     if (mHandle==0 || mClient==0) {
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 008446b..eec97be 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_SRC_FILES:= \
 	Fence.cpp \
 	FramebufferNativeWindow.cpp \
+	FrameStats.cpp \
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
diff --git a/libs/ui/FrameStats.cpp b/libs/ui/FrameStats.cpp
new file mode 100644
index 0000000..acbe27e
--- /dev/null
+++ b/libs/ui/FrameStats.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 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 <ui/FrameStats.h>
+
+namespace android {
+
+bool FrameStats::isFixedSize() const {
+    return false;
+}
+
+size_t FrameStats::getFlattenedSize() const {
+    const size_t timestampSize = sizeof(nsecs_t);
+
+    size_t size = timestampSize;
+    size += 3 * desiredPresentTimesNano.size() * timestampSize;
+
+    return size;
+}
+
+status_t FrameStats::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    nsecs_t* timestamps = reinterpret_cast<nsecs_t*>(buffer);
+    const size_t timestampSize = sizeof(nsecs_t);
+    size_t frameCount = desiredPresentTimesNano.size();
+
+    memcpy(timestamps, &refreshPeriodNano, timestampSize);
+    timestamps += 1;
+
+    memcpy(timestamps, desiredPresentTimesNano.array(), frameCount * timestampSize);
+    timestamps += frameCount;
+
+    memcpy(timestamps, actualPresentTimesNano.array(), frameCount * timestampSize);
+    timestamps += frameCount;
+
+    memcpy(timestamps, frameReadyTimesNano.array(), frameCount * timestampSize);
+
+    return NO_ERROR;
+}
+
+status_t FrameStats::unflatten(void const* buffer, size_t size) {
+    const size_t timestampSize = sizeof(nsecs_t);
+
+    if (size < timestampSize) {
+        return NO_MEMORY;
+    }
+
+    nsecs_t const* timestamps = reinterpret_cast<nsecs_t const*>(buffer);
+    size_t frameCount = (size - timestampSize) / (3 * timestampSize);
+
+    memcpy(&refreshPeriodNano, timestamps, timestampSize);
+    timestamps += 1;
+
+    desiredPresentTimesNano.resize(frameCount);
+    memcpy(desiredPresentTimesNano.editArray(), timestamps, frameCount * timestampSize);
+    timestamps += frameCount;
+
+    actualPresentTimesNano.resize(frameCount);
+    memcpy(actualPresentTimesNano.editArray(), timestamps, frameCount * timestampSize);
+    timestamps += frameCount;
+
+    frameReadyTimesNano.resize(frameCount);
+    memcpy(frameReadyTimesNano.editArray(), timestamps, frameCount * timestampSize);
+
+    return NO_ERROR;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 975631c..f7d32d0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -155,5 +155,23 @@
     return mFlinger->onLayerRemoved(this, handle);
 }
 
+status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
+    sp<Layer> layer = getLayerUser(handle);
+    if (layer == NULL) {
+        return NAME_NOT_FOUND;
+    }
+    layer->clearFrameStats();
+    return NO_ERROR;
+}
+
+status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
+    sp<Layer> layer = getLayerUser(handle);
+    if (layer == NULL) {
+        return NAME_NOT_FOUND;
+    }
+    layer->getFrameStats(outStats);
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 84e649f..b6d7381 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -60,6 +60,10 @@
 
     virtual status_t destroySurface(const sp<IBinder>& handle);
 
+    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
+
+    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
+
     virtual status_t onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
 
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 2fb665e..c09bbe4 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -22,6 +22,7 @@
 #include <cutils/log.h>
 
 #include <ui/Fence.h>
+#include <ui/FrameStats.h>
 
 #include <utils/String8.h>
 
@@ -100,7 +101,7 @@
     processFencesLocked();
 }
 
-void FrameTracker::clear() {
+void FrameTracker::clearStats() {
     Mutex::Autolock lock(mMutex);
     for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
         mFrameRecords[i].desiredPresentTime = 0;
@@ -115,6 +116,32 @@
     mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
 }
 
+void FrameTracker::getStats(FrameStats* outStats) const {
+    Mutex::Autolock lock(mMutex);
+    processFencesLocked();
+
+    outStats->refreshPeriodNano = mDisplayPeriod;
+
+    const size_t offset = mOffset;
+    for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
+        const size_t index = (offset + i) % NUM_FRAME_RECORDS;
+
+        // Skip frame records with no data (if buffer not yet full).
+        if (mFrameRecords[index].desiredPresentTime == 0) {
+            continue;
+        }
+
+        nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime;
+        outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano);
+
+        nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime;
+        outStats->actualPresentTimesNano.push_back(actualPresentTimeNano);
+
+        nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime;
+        outStats->frameReadyTimesNano.push_back(frameReadyTimeNano);
+    }
+}
+
 void FrameTracker::logAndResetStats(const String8& name) {
     Mutex::Autolock lock(mMutex);
     logStatsLocked(name);
@@ -206,7 +233,7 @@
             mFrameRecords[idx].actualPresentTime < INT64_MAX;
 }
 
-void FrameTracker::dump(String8& result) const {
+void FrameTracker::dumpStats(String8& result) const {
     Mutex::Autolock lock(mMutex);
     processFencesLocked();
 
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 9233247..cd5e3f3 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -78,15 +78,18 @@
     // advanceFrame advances the frame tracker to the next frame.
     void advanceFrame();
 
-    // clear resets all the tracked frame data to zero.
-    void clear();
+    // clearStats clears the tracked frame stats.
+    void clearStats();
+
+    // getStats gets the tracked frame stats.
+    void getStats(FrameStats* outStats) const;
 
     // 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;
+    // dumpStats dump appends the current frame display time history to the result string.
+    void dumpStats(String8& result) const;
 
 private:
     struct FrameRecord {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7f2ee2a..9920525 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1244,18 +1244,22 @@
     }
 }
 
-void Layer::dumpStats(String8& result) const {
-    mFrameTracker.dump(result);
+void Layer::dumpFrameStats(String8& result) const {
+    mFrameTracker.dumpStats(result);
 }
 
-void Layer::clearStats() {
-    mFrameTracker.clear();
+void Layer::clearFrameStats() {
+    mFrameTracker.clearStats();
 }
 
 void Layer::logFrameStats() {
     mFrameTracker.logAndResetStats(mName);
 }
 
+void Layer::getFrameStats(FrameStats* outStats) const {
+    mFrameTracker.getStats(outStats);
+}
+
 // ---------------------------------------------------------------------------
 
 Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8f8989e..62970c3 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -27,6 +27,7 @@
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
+#include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
@@ -288,9 +289,10 @@
 
     /* always call base class first */
     void dump(String8& result, Colorizer& colorizer) const;
-    void dumpStats(String8& result) const;
-    void clearStats();
+    void dumpFrameStats(String8& result) const;
+    void clearFrameStats();
     void logFrameStats();
+    void getFrameStats(FrameStats* outStats) const;
 
 protected:
     // constant
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d084bf5..a346520 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -574,6 +574,18 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::clearAnimationFrameStats() {
+    Mutex::Autolock _l(mStateLock);
+    mAnimFrameTracker.clearStats();
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
+    Mutex::Autolock _l(mStateLock);
+    mAnimFrameTracker.getStats(outStats);
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -2255,14 +2267,14 @@
     result.appendFormat("%" PRId64 "\n", period);
 
     if (name.isEmpty()) {
-        mAnimFrameTracker.dump(result);
+        mAnimFrameTracker.dumpStats(result);
     } else {
         const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
         const size_t count = currentLayers.size();
         for (size_t i=0 ; i<count ; i++) {
             const sp<Layer>& layer(currentLayers[i]);
             if (name == layer->getName()) {
-                layer->dumpStats(result);
+                layer->dumpFrameStats(result);
             }
         }
     }
@@ -2282,11 +2294,11 @@
     for (size_t i=0 ; i<count ; i++) {
         const sp<Layer>& layer(currentLayers[i]);
         if (name.isEmpty() || (name == layer->getName())) {
-            layer->clearStats();
+            layer->clearFrameStats();
         }
     }
 
-    mAnimFrameTracker.clear();
+    mAnimFrameTracker.clearStats();
 }
 
 // This should only be called from the main thread.  Otherwise it would need
@@ -2500,6 +2512,8 @@
         case BOOT_FINISHED:
         case BLANK:
         case UNBLANK:
+        case CLEAR_ANIMATION_FRAME_STATS:
+        case GET_ANIMATION_FRAME_STATS:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 630f4b7..717ee66 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -210,6 +210,8 @@
     // called when screen is turning back on
     virtual void unblank(const sp<IBinder>& display);
     virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info);
+    virtual status_t clearAnimationFrameStats();
+    virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface