diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 61edbff31..13d1a5579 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -90,7 +90,7 @@ else endif LOCAL_CFLAGS += -fvisibility=hidden -Werror=format -LOCAL_CPPFLAGS := -std=c++11 +LOCAL_CPPFLAGS := -std=c++1y LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -110,6 +110,8 @@ LOCAL_MODULE := libsurfaceflinger LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code +include external/libcxx/libcxx.mk + include $(BUILD_SHARED_LIBRARY) ############################################################### diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 34192951a..3077d0a3f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -78,6 +78,12 @@ #include "RenderEngine/RenderEngine.h" #include +#include +#include +#include +#include +#include + #define DISPLAY_COUNT 1 /* @@ -1807,6 +1813,17 @@ void SurfaceFlinger::doDisplayComposition(const sp& hw, hw->swapBuffers(getHwComposer()); } +static std::set getOpenFds() +{ + std::set fds; + for (int fd = 0; fd < 1024; ++fd) { + if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) { + fds.insert(fd); + } + } + return fds; +} + bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const Region& dirty) { RenderEngine& engine(getRenderEngine()); @@ -1881,6 +1898,8 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const * and then, render the layers targeted at the framebuffer */ + static std::set previousLayers; + std::set currentLayers; const Vector< sp >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); const Transform& tr = hw->getTransform(); @@ -1890,6 +1909,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const const sp& layer(layers[i]); const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { + currentLayers.insert(layer->getName().string()); switch (cur->getCompositionType()) { case HWC_CURSOR_OVERLAY: case HWC_OVERLAY: { @@ -1925,11 +1945,86 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const const Region clip(dirty.intersect( tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { + currentLayers.insert(layer->getName().string()); layer->draw(hw, clip); } } } + std::set newLayers; + for (auto layer : currentLayers) { + if (previousLayers.count(layer) == 0) { + newLayers.insert(layer); + } + } + std::set deletedLayers; + for (auto layer : previousLayers) { + if (currentLayers.count(layer) == 0) { + deletedLayers.insert(layer); + } + } + previousLayers = std::move(currentLayers); + + static std::set previousFds; + static std::unordered_map> initialFds; + + for (auto layer : newLayers) { + initialFds[layer] = previousFds; + } + + std::set currentFds = getOpenFds(); + + if (!deletedLayers.empty()) { + std::unordered_map> currentBlame; + static std::map> persistentBlame; + for (auto layer : deletedLayers) { + std::vector newFds; + auto& layerInitialFds = initialFds[layer]; + std::set_difference( + currentFds.cbegin(), currentFds.cend(), + layerInitialFds.cbegin(), layerInitialFds.cend(), + std::back_inserter(newFds)); + + for (auto fd : newFds) { + currentBlame[fd].insert(layer); + } + + initialFds.erase(layer); + } + + for (auto blame : currentBlame) { + persistentBlame[blame.first] = blame.second; + } + + auto iter = persistentBlame.cbegin(); + while (iter != persistentBlame.cend()) { + if (currentFds.count(iter->first) == 0) { + iter = persistentBlame.erase(iter); + } else { + ++iter; + } + } + + std::map, int> blameCounts; + for (auto blame : persistentBlame) { + ++blameCounts[blame.second]; + } + + ALOGI("FD Blame: %d open fds", currentFds.size()); + for (auto blame : blameCounts) { + std::string layers; + for (auto layer : blame.first) { + if (!layers.empty()) { + layers += ", "; + } + layers += layer; + } + ALOGI(" %s: %d", layers.c_str(), blame.second); + } + } + + previousFds = std::move(currentFds); + // disable scissor at the end of the frame engine.disableScissor(); return true;