Merge "Refactor argument parsing in ota preopt"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index cce0579..40566e0 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1621,7 +1621,7 @@
" -p: capture screenshot to filename.png (requires -o)\n"
" -z: generate zipped file (requires -o)\n"
" -s: write output to control socket (for init)\n"
- " -S: write file location to control socket (for init; requires -o and -z)"
+ " -S: write file location to control socket (for init; requires -o and -z)\n"
" -q: disable vibrate\n"
" -B: send broadcast when finished (requires -o)\n"
" -P: send broadcast when started and update system properties on "
@@ -2213,9 +2213,11 @@
}
/* vibrate a few but shortly times to let user know it's finished */
- for (int i = 0; i < 3; i++) {
- Vibrate(75);
- usleep((75 + 50) * 1000);
+ if (do_vibrate) {
+ for (int i = 0; i < 3; i++) {
+ Vibrate(75);
+ usleep((75 + 50) * 1000);
+ }
}
/* tell activity manager we're done */
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index abbd62d..013a3c1 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -715,13 +715,20 @@
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd, const std::vector<unique_fd>* apk_fds = nullptr) {
+static void run_profman(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>* apk_fds,
+ bool copy_and_update) {
const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
- std::vector<std::string> profile_args(profiles_fd.size());
- for (size_t k = 0; k < profiles_fd.size(); k++) {
- profile_args[k] = "--profile-file-fd=" + std::to_string(profiles_fd[k].get());
+ if (copy_and_update) {
+ CHECK_EQ(1u, profile_fds.size());
+ CHECK(apk_fds != nullptr);
+ CHECK_EQ(1u, apk_fds->size());
+ }
+ std::vector<std::string> profile_args(profile_fds.size());
+ for (size_t k = 0; k < profile_fds.size(); k++) {
+ profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
}
std::string reference_profile_arg = "--reference-profile-file-fd="
+ std::to_string(reference_profile_fd.get());
@@ -734,7 +741,7 @@
}
// program name, reference profile fd, the final NULL and the profile fds
- const char* argv[3 + profile_args.size() + apk_args.size()];
+ const char* argv[3 + profile_args.size() + apk_args.size() + (copy_and_update ? 1 : 0)];
int i = 0;
argv[i++] = profman_bin;
argv[i++] = reference_profile_arg.c_str();
@@ -744,6 +751,9 @@
for (size_t k = 0; k < apk_args.size(); k++) {
argv[i++] = apk_args[k].c_str();
}
+ if (copy_and_update) {
+ argv[i++] = "--copy-and-update-profile-key";
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -752,6 +762,25 @@
exit(68); /* only get here on exec failure */
}
+
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>* apk_fds = nullptr) {
+ run_profman(profiles_fd, reference_profile_fd, apk_fds, /*copy_and_update*/false);
+}
+
+
+static void run_profman_copy_and_update(unique_fd&& profile_fd,
+ unique_fd&& reference_profile_fd,
+ unique_fd&& apk_fd) {
+ std::vector<unique_fd> profiles_fd;
+ profiles_fd.push_back(std::move(profile_fd));
+ std::vector<unique_fd> apk_fds;
+ apk_fds.push_back(std::move(apk_fd));
+
+ run_profman(profiles_fd, reference_profile_fd, &apk_fds, /*copy_and_update*/true);
+}
+
// Decides if profile guided compilation is needed or not based on existing profiles.
// The location is the package name for primary apks or the dex path for secondary dex files.
// Returns true if there is enough information in the current profiles that makes it
@@ -2610,7 +2639,7 @@
userid_t user_id,
appid_t app_id,
const std::string& profile_name,
- const std::string& code_path ATTRIBUTE_UNUSED,
+ const std::string& code_path,
const std::unique_ptr<std::string>& dex_metadata) {
// Prepare the current profile.
std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name,
@@ -2631,8 +2660,11 @@
/*read_write*/ true, /*is_secondary_dex*/ false);
unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY(
open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW)));
- std::vector<unique_fd> profiles_fd;
- profiles_fd.push_back(std::move(dex_metadata_fd));
+ unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW)));
+ if (apk_fd < 0) {
+ PLOG(ERROR) << "Could not open code path " << code_path;
+ return false;
+ }
pid_t pid = fork();
if (pid == 0) {
@@ -2640,10 +2672,10 @@
gid_t app_shared_gid = multiuser_get_shared_gid(user_id, app_id);
drop_capabilities(app_shared_gid);
- // TODO(calin): the dex metadata profile might embed different names for the
- // same code path (e.g. YouTube.apk or base.apk, depending on how the initial
- // profile was captured). We should pass the code path to adjust the names in the profile.
- run_profman_merge(profiles_fd, ref_profile_fd);
+ // The copy and update takes ownership over the fds.
+ run_profman_copy_and_update(std::move(dex_metadata_fd),
+ std::move(ref_profile_fd),
+ std::move(apk_fd));
exit(42); /* only get here on exec failure */
}
diff --git a/data/etc/android.hardware.vulkan.version-1_1.xml b/data/etc/android.hardware.vulkan.version-1_1.xml
new file mode 100644
index 0000000..9704e0f
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.version-1_1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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 is the standard feature indicating that the device has a Vulkan
+ driver that supports API version 1.1 (0x00401000) -->
+<permissions>
+ <feature name="android.hardware.vulkan.version" version="4198400" />
+</permissions>
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 939a209..c40cad3 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -615,7 +615,7 @@
windowType, ownerUid, &handle, &gbp);
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- sur = new SurfaceControl(this, handle, gbp);
+ sur = new SurfaceControl(this, handle, gbp, true /* owned */);
}
}
return sur;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index f5fb8ac..5eafbb3 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -48,8 +48,9 @@
SurfaceControl::SurfaceControl(
const sp<SurfaceComposerClient>& client,
const sp<IBinder>& handle,
- const sp<IGraphicBufferProducer>& gbp)
- : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
+ const sp<IGraphicBufferProducer>& gbp,
+ bool owned)
+ : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned)
{
}
@@ -60,7 +61,9 @@
void SurfaceControl::destroy()
{
- if (isValid()) {
+ // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
+ // retrieved it from another process.
+ if (isValid() && mOwned) {
mClient->destroySurface(mHandle);
}
// clear all references and trigger an IPC now, to make sure things
@@ -184,9 +187,11 @@
}
sp<IBinder> gbp;
parcel->readNullableStrongBinder(&gbp);
+
+ // We aren't the original owner of the surface.
return new SurfaceControl(new SurfaceComposerClient(
interface_cast<ISurfaceComposerClient>(client)),
- handle.get(), interface_cast<IGraphicBufferProducer>(gbp));
+ handle.get(), interface_cast<IGraphicBufferProducer>(gbp), false /* owned */);
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 1416d87..bd987dd 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -87,7 +87,8 @@
SurfaceControl(
const sp<SurfaceComposerClient>& client,
const sp<IBinder>& handle,
- const sp<IGraphicBufferProducer>& gbp);
+ const sp<IGraphicBufferProducer>& gbp,
+ bool owned);
~SurfaceControl();
@@ -100,6 +101,7 @@
sp<IGraphicBufferProducer> mGraphicBufferProducer;
mutable Mutex mLock;
mutable sp<Surface> mSurfaceData;
+ bool mOwned;
};
}; // namespace android
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 153d35a..b92cbf3 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -42,8 +42,8 @@
for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
bits = bits | bit;
}
- // TODO(b/72323293): Remove this mask for EXTERNAL_DISP.
- bits = bits | (1 << 13);
+ // TODO(b/72323293, b/72703005): Remove these additional bits
+ bits = bits | (1 << 10) | (1 << 13);
return bits;
}();
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 1c5b2d6..9b6f0c5 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -26,7 +26,6 @@
includeFiles = [ "include" ]
staticLibraries = [
- "libsurfaceflingerincludes",
"libbufferhub",
"libbufferhubqueue",
"libdisplay",
@@ -63,8 +62,9 @@
]
headerLibraries = [
- "libdvr_headers",
"android.hardware.graphics.composer@2.1-command-buffer",
+ "libdvr_headers",
+ "libsurfaceflinger_headers",
]
cc_library_static {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 484e0ba..26ae13d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -513,11 +513,11 @@
found = true;
}
}
- if (found && dp->haveExtension("EGL_KHR_gl_colorspace")) {
- stripped = true;
- } else {
+ if (found || !dp->haveExtension("EGL_KHR_gl_colorspace")) {
stripped_attrib_list.push_back(attr[0]);
stripped_attrib_list.push_back(attr[1]);
+ } else {
+ stripped = true;
}
}
break;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index bd7f0ea..4ed4392 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,8 +1,210 @@
-cc_library_static {
- name: "libsurfaceflingerincludes",
+cc_defaults {
+ name: "surfaceflinger_defaults",
+ cflags: [
+ "-DLOG_TAG=\"SurfaceFlinger\"",
+ "-Wall",
+ "-Werror",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ cppflags: ["-std=c++1z"],
+}
+
+cc_defaults {
+ name: "libsurfaceflinger_defaults",
+ defaults: ["surfaceflinger_defaults"],
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ ],
+ shared_libs: [
+ "android.frameworks.vr.composer@1.0",
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.power@1.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libdl",
+ "libEGL",
+ "libfmq",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libgui",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblayers_proto",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libsync",
+ "libui",
+ "libutils",
+ "libvulkan",
+ ],
+ static_libs: [
+ "libserviceutils",
+ "libtrace_proto",
+ "libvkjson",
+ "libvr_manager",
+ "libvrflinger",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_static_lib_headers: [
+ "libserviceutils",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ ],
+}
+
+cc_library_headers {
+ name: "libsurfaceflinger_headers",
export_include_dirs: ["."],
static_libs = ["libserviceutils"],
export_static_lib_headers = ["libserviceutils"],
}
-subdirs = ["tests/fakehwc", "layerproto"]
\ No newline at end of file
+filegroup {
+ name: "libsurfaceflinger_sources",
+ srcs: [
+ "BufferLayer.cpp",
+ "BufferLayerConsumer.cpp",
+ "Client.cpp",
+ "ColorLayer.cpp",
+ "DisplayDevice.cpp",
+ "DisplayHardware/ComposerHal.cpp",
+ "DisplayHardware/FramebufferSurface.cpp",
+ "DisplayHardware/HWC2.cpp",
+ "DisplayHardware/HWComposer.cpp",
+ "DisplayHardware/HWComposerBufferCache.cpp",
+ "DisplayHardware/VirtualDisplaySurface.cpp",
+ "DispSync.cpp",
+ "Effects/Daltonizer.cpp",
+ "EventControlThread.cpp",
+ "EventLog/EventLog.cpp",
+ "EventThread.cpp",
+ "FrameTracker.cpp",
+ "GpuService.cpp",
+ "Layer.cpp",
+ "LayerProtoHelper.cpp",
+ "LayerRejecter.cpp",
+ "LayerVector.cpp",
+ "MessageQueue.cpp",
+ "MonitoredProducer.cpp",
+ "RenderArea.cpp",
+ "RenderEngine/Description.cpp",
+ "RenderEngine/GLES20RenderEngine.cpp",
+ "RenderEngine/GLExtensions.cpp",
+ "RenderEngine/Image.cpp",
+ "RenderEngine/Mesh.cpp",
+ "RenderEngine/Program.cpp",
+ "RenderEngine/ProgramCache.cpp",
+ "RenderEngine/RenderEngine.cpp",
+ "RenderEngine/Surface.cpp",
+ "RenderEngine/Texture.cpp",
+ "StartPropertySetThread.cpp",
+ "SurfaceFlinger.cpp",
+ "SurfaceInterceptor.cpp",
+ "SurfaceTracing.cpp",
+ "Transform.cpp",
+ ],
+}
+
+cc_library_shared {
+ name: "libsurfaceflinger",
+ defaults: ["libsurfaceflinger_defaults"],
+ cflags: [
+ "-fvisibility=hidden",
+ "-Werror=format",
+ ],
+ srcs: [
+ ":libsurfaceflinger_sources",
+ ],
+ logtags: ["EventLog/EventLogTags.logtags"],
+ include_dirs: [
+ "external/vulkan-validation-layers/libs/vkjson",
+ "frameworks/native/vulkan/include",
+ ],
+ cppflags: [
+ "-fwhole-program-vtables", // requires ThinLTO
+ ],
+ lto: {
+ thin: true,
+ },
+}
+
+cc_binary {
+ name: "surfaceflinger",
+ defaults: ["surfaceflinger_defaults"],
+ init_rc: ["surfaceflinger.rc"],
+ srcs: ["main_surfaceflinger.cpp"],
+ whole_static_libs: [
+ "libsigchain",
+ ],
+ shared_libs: [
+ "android.frameworks.displayservice@1.0",
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "libbinder",
+ "libcutils",
+ "libdisplayservicehidl",
+ "libhidlbase",
+ "libhidltransport",
+ "liblayers_proto",
+ "liblog",
+ "libsurfaceflinger",
+ "libutils",
+ ],
+ static_libs: [
+ "libserviceutils",
+ "libtrace_proto",
+ ],
+ ldflags: ["-Wl,--export-dynamic"],
+
+ // TODO(b/71715793): These version-scripts are required due to the use of
+ // whole_static_libs to pull in libsigchain. To work, the files had to be
+ // locally duplicated from their original location
+ // $ANDROID_ROOT/art/sigchainlib/
+ multilib: {
+ lib32: {
+ version_script: "version-script32.txt",
+ },
+ lib64: {
+ version_script: "version-script64.txt",
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libsurfaceflinger_ddmconnection",
+ defaults: ["surfaceflinger_defaults"],
+ srcs: ["DdmConnection.cpp"],
+ shared_libs: [
+ "libcutils",
+ "libdl",
+ "liblog",
+ ],
+ product_variables: {
+ // uses jni which may not be available in PDK
+ pdk: {
+ enabled: false,
+ },
+ },
+}
+
+subdirs = [
+ "layerproto",
+ "tests",
+]
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
deleted file mode 100644
index 6c54ec3..0000000
--- a/services/surfaceflinger/Android.mk
+++ /dev/null
@@ -1,183 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := \
- Client.cpp \
- DisplayDevice.cpp \
- DispSync.cpp \
- EventControlThread.cpp \
- StartPropertySetThread.cpp \
- EventThread.cpp \
- FrameTracker.cpp \
- GpuService.cpp \
- Layer.cpp \
- BufferLayer.cpp \
- BufferLayerConsumer.cpp \
- ColorLayer.cpp \
- LayerRejecter.cpp \
- LayerVector.cpp \
- MessageQueue.cpp \
- MonitoredProducer.cpp \
- SurfaceFlinger.cpp \
- SurfaceInterceptor.cpp \
- SurfaceTracing.cpp \
- Transform.cpp \
- DisplayHardware/ComposerHal.cpp \
- DisplayHardware/FramebufferSurface.cpp \
- DisplayHardware/HWC2.cpp \
- DisplayHardware/HWComposer.cpp \
- DisplayHardware/HWComposerBufferCache.cpp \
- DisplayHardware/VirtualDisplaySurface.cpp \
- Effects/Daltonizer.cpp \
- EventLog/EventLogTags.logtags \
- EventLog/EventLog.cpp \
- RenderEngine/Description.cpp \
- RenderEngine/Image.cpp \
- RenderEngine/Mesh.cpp \
- RenderEngine/Program.cpp \
- RenderEngine/ProgramCache.cpp \
- RenderEngine/GLExtensions.cpp \
- RenderEngine/RenderEngine.cpp \
- RenderEngine/Surface.cpp \
- RenderEngine/Texture.cpp \
- RenderEngine/GLES20RenderEngine.cpp \
- LayerProtoHelper.cpp \
- RenderArea.cpp \
-
-LOCAL_MODULE := libsurfaceflinger
-LOCAL_C_INCLUDES := \
- frameworks/native/vulkan/include \
- external/vulkan-validation-layers/libs/vkjson \
- system/libhwbinder/fast_msgq/include \
-
-LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-
-LOCAL_STATIC_LIBRARIES := \
- libtrace_proto \
- libvkjson \
- libvr_manager \
- libvrflinger \
- libserviceutils
-
-LOCAL_HEADER_LIBRARIES := \
- android.hardware.graphics.composer@2.1-command-buffer
-
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libserviceutils
-
-LOCAL_SHARED_LIBRARIES := \
- android.frameworks.vr.composer@1.0 \
- android.hardware.graphics.allocator@2.0 \
- android.hardware.graphics.composer@2.1 \
- android.hardware.configstore@1.0 \
- android.hardware.configstore-utils \
- libcutils \
- liblog \
- libdl \
- libfmq \
- libhardware \
- libhidlbase \
- libhidltransport \
- libhwbinder \
- libutils \
- libEGL \
- libGLESv1_CM \
- libGLESv2 \
- libbinder \
- libui \
- libgui \
- libvulkan \
- libsync \
- libprotobuf-cpp-lite \
- libbase \
- android.hardware.power@1.0 \
- liblayers_proto
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
- android.hardware.graphics.allocator@2.0 \
- android.hardware.graphics.composer@2.1 \
- libhidlbase \
- libhidltransport \
- libhwbinder
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################
-# build surfaceflinger's executable
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-
-LOCAL_INIT_RC := surfaceflinger.rc
-
-LOCAL_SRC_FILES := \
- main_surfaceflinger.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- android.frameworks.displayservice@1.0 \
- android.hardware.configstore@1.0 \
- android.hardware.configstore-utils \
- android.hardware.graphics.allocator@2.0 \
- libsurfaceflinger \
- libcutils \
- libdisplayservicehidl \
- liblog \
- libbinder \
- libhidlbase \
- libhidltransport \
- libutils \
- libui \
- libgui \
- libdl \
- liblayers_proto
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_STATIC_LIBRARIES := libtrace_proto \
- libserviceutils
-
-LOCAL_MODULE := surfaceflinger
-
-ifdef TARGET_32_BIT_SURFACEFLINGER
-LOCAL_32_BIT_ONLY := true
-endif
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z
-
-include $(BUILD_EXECUTABLE)
-
-###############################################################
-# uses jni which may not be available in PDK
-ifneq ($(wildcard libnativehelper/include),)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-
-LOCAL_SRC_FILES := \
- DdmConnection.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libdl
-
-LOCAL_MODULE := libsurfaceflinger_ddmconnection
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
-endif # libnativehelper
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bef12ea..9e01fd0 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -33,8 +33,8 @@
#include <ui/FenceTime.h>
#include "DispSync.h"
-#include "SurfaceFlinger.h"
#include "EventLog/EventLog.h"
+#include "SurfaceFlinger.h"
using std::max;
using std::min;
@@ -53,15 +53,14 @@
// needed to re-synchronize the software vsync model with the hardware. The
// error metric used is the mean of the squared difference between each
// present time and the nearest software-predicted vsync.
-static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
+static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
#undef LOG_TAG
#define LOG_TAG "DispSyncThread"
-class DispSyncThread: public Thread {
+class DispSyncThread : public Thread {
public:
-
- explicit DispSyncThread(const char* name):
- mName(name),
+ explicit DispSyncThread(const char* name)
+ : mName(name),
mStop(false),
mPeriod(0),
mPhase(0),
@@ -78,8 +77,8 @@
mPhase = phase;
mReferenceTime = referenceTime;
ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
- " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
- ns2us(mPhase), ns2us(mReferenceTime));
+ " mReferenceTime = %" PRId64,
+ mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
mCond.signal();
}
@@ -115,8 +114,7 @@
if (mPeriod == 0) {
err = mCond.wait(mMutex);
if (err != NO_ERROR) {
- ALOGE("error waiting for new events: %s (%d)",
- strerror(-err), err);
+ ALOGE("error waiting for new events: %s (%d)", strerror(-err), err);
return false;
}
continue;
@@ -133,16 +131,14 @@
ALOGV("[%s] Waiting forever", mName);
err = mCond.wait(mMutex);
} else {
- ALOGV("[%s] Waiting until %" PRId64, mName,
- ns2us(targetTime));
+ ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime));
err = mCond.waitRelative(mMutex, targetTime - now);
}
if (err == TIMED_OUT) {
isWakeup = true;
} else if (err != NO_ERROR) {
- ALOGE("error waiting for next event: %s (%d)",
- strerror(-err), err);
+ ALOGE("error waiting for next event: %s (%d)", strerror(-err), err);
return false;
}
}
@@ -153,8 +149,7 @@
static const nsecs_t kMaxWakeupLatency = us2ns(1500);
if (isWakeup) {
- mWakeupLatency = ((mWakeupLatency * 63) +
- (now - targetTime)) / 64;
+ mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
@@ -173,8 +168,7 @@
return false;
}
- status_t addEventListener(const char* name, nsecs_t phase,
- const sp<DispSync::Callback>& callback) {
+ status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
@@ -191,8 +185,7 @@
// We want to allow the firstmost future event to fire without
// allowing any past events to fire
- listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
- mWakeupLatency;
+ listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
mEventListeners.push(listener);
@@ -201,7 +194,7 @@
return NO_ERROR;
}
- status_t removeEventListener(const sp<DispSync::Callback>& callback) {
+ status_t removeEventListener(DispSync::Callback* callback) {
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
@@ -225,16 +218,15 @@
}
private:
-
struct EventListener {
const char* mName;
nsecs_t mPhase;
nsecs_t mLastEventTime;
- sp<DispSync::Callback> mCallback;
+ DispSync::Callback* mCallback;
};
struct CallbackInvocation {
- sp<DispSync::Callback> mCallback;
+ DispSync::Callback* mCallback;
nsecs_t mEventTime;
};
@@ -243,8 +235,7 @@
ALOGV("[%s] computeNextEventTimeLocked", mName);
nsecs_t nextEventTime = INT64_MAX;
for (size_t i = 0; i < mEventListeners.size(); i++) {
- nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
- now);
+ nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now);
if (t < nextEventTime) {
nextEventTime = t;
@@ -257,22 +248,19 @@
Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
- ns2us(now));
+ ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
Vector<CallbackInvocation> callbackInvocations;
nsecs_t onePeriodAgo = now - mPeriod;
for (size_t i = 0; i < mEventListeners.size(); i++) {
- nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
- onePeriodAgo);
+ nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo);
if (t < now) {
CallbackInvocation ci;
ci.mCallback = mEventListeners[i].mCallback;
ci.mEventTime = t;
- ALOGV("[%s] [%s] Preparing to fire", mName,
- mEventListeners[i].mName);
+ ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName);
callbackInvocations.push(ci);
mEventListeners.editItemAt(i).mLastEventTime = t;
}
@@ -281,18 +269,16 @@
return callbackInvocations;
}
- nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
- nsecs_t baseTime) {
+ nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
- mName, listener.mName, ns2us(baseTime));
+ ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
+ ns2us(baseTime));
nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
if (baseTime < lastEventTime) {
baseTime = lastEventTime;
- ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
- ns2us(baseTime));
+ ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime));
}
baseTime -= mReferenceTime;
@@ -374,11 +360,8 @@
bool mParity;
};
-DispSync::DispSync(const char* name) :
- mName(name),
- mRefreshSkipCount(0),
- mThread(new DispSyncThread(name)) {
-}
+DispSync::DispSync(const char* name)
+ : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
DispSync::~DispSync() {}
@@ -404,7 +387,8 @@
// not needed because any time there is an event registered we will
// turn on the HW vsync events.
if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
- addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
+ mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
+ addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
}
}
}
@@ -451,8 +435,8 @@
mPhase = 0;
mReferenceTime = timestamp;
ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
- "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
- ns2us(mReferenceTime));
+ "mReferenceTime = %" PRId64,
+ mName, ns2us(mPeriod), ns2us(mReferenceTime));
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
@@ -480,16 +464,13 @@
// Check against kErrorThreshold / 2 to add some hysteresis before having to
// resync again
bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
- ALOGV("[%s] addResyncSample returning %s", mName,
- modelLocked ? "locked" : "unlocked");
+ ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
return !modelLocked;
}
-void DispSync::endResync() {
-}
+void DispSync::endResync() {}
-status_t DispSync::addEventListener(const char* name, nsecs_t phase,
- const sp<Callback>& callback) {
+status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback) {
Mutex::Autolock lock(mMutex);
return mThread->addEventListener(name, phase, callback);
}
@@ -501,7 +482,7 @@
updateModelLocked();
}
-status_t DispSync::removeEventListener(const sp<Callback>& callback) {
+status_t DispSync::removeEventListener(Callback* callback) {
Mutex::Autolock lock(mMutex);
return mThread->removeEventListener(callback);
}
@@ -597,8 +578,7 @@
// call getSignalTime() periodically so the cache is updated when the
// fence signals.
nsecs_t time = mPresentFences[i]->getCachedSignalTime();
- if (time == Fence::SIGNAL_TIME_PENDING ||
- time == Fence::SIGNAL_TIME_INVALID) {
+ if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) {
continue;
}
@@ -622,9 +602,8 @@
mError = 0;
// Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
mZeroErrSamplesCount++;
- ALOGE_IF(
- (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
- "No present times for model error.");
+ ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+ "No present times for model error.");
}
if (kTraceDetailedInfo) {
@@ -650,17 +629,14 @@
void DispSync::dump(String8& result) const {
Mutex::Autolock lock(mMutex);
- result.appendFormat("present fences are %s\n",
- mIgnorePresentFences ? "ignored" : "used");
- result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
- mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
+ result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
+ result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
+ 1000000000.0 / mPeriod, mRefreshSkipCount);
result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
- result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
- mError, sqrt(mError));
+ result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n",
- mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
- result.appendFormat("mNumResyncSamples: %zd (max %d)\n",
- mNumResyncSamples, MAX_RESYNC_SAMPLES);
+ mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
+ result.appendFormat("mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, MAX_RESYNC_SAMPLES);
result.appendFormat("mResyncSamples:\n");
nsecs_t previous = -1;
@@ -670,14 +646,13 @@
if (i == 0) {
result.appendFormat(" %" PRId64 "\n", sampleTime);
} else {
- result.appendFormat(" %" PRId64 " (+%" PRId64 ")\n",
- sampleTime, sampleTime - previous);
+ result.appendFormat(" %" PRId64 " (+%" PRId64 ")\n", sampleTime,
+ sampleTime - previous);
}
previous = sampleTime;
}
- result.appendFormat("mPresentFences [%d]:\n",
- NUM_PRESENT_SAMPLES);
+ result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
previous = Fence::SIGNAL_TIME_INVALID;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
@@ -685,17 +660,16 @@
nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
if (presentTime == Fence::SIGNAL_TIME_PENDING) {
result.appendFormat(" [unsignaled fence]\n");
- } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+ } else if (presentTime == Fence::SIGNAL_TIME_INVALID) {
result.appendFormat(" [invalid fence]\n");
} else if (previous == Fence::SIGNAL_TIME_PENDING ||
- previous == Fence::SIGNAL_TIME_INVALID) {
+ previous == Fence::SIGNAL_TIME_INVALID) {
result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime,
- (now - presentTime) / 1000000.0);
+ (now - presentTime) / 1000000.0);
} else {
- result.appendFormat(" %" PRId64 " (+%" PRId64 " / %.3f) (%.3f ms ago)\n",
- presentTime, presentTime - previous,
- (presentTime - previous) / (double) mPeriod,
- (now - presentTime) / 1000000.0);
+ result.appendFormat(" %" PRId64 " (+%" PRId64 " / %.3f) (%.3f ms ago)\n", presentTime,
+ presentTime - previous, (presentTime - previous) / (double)mPeriod,
+ (now - presentTime) / 1000000.0);
}
previous = presentTime;
}
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 880a24d..9336f4d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -20,8 +20,8 @@
#include <stddef.h>
#include <utils/Mutex.h>
-#include <utils/Timers.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <ui/FenceTime.h>
@@ -47,12 +47,10 @@
// false to indicate that a resynchronization (via addResyncSample) is not
// needed.
class DispSync {
-
public:
-
- class Callback: public virtual RefBase {
+ class Callback {
public:
- virtual ~Callback() {};
+ virtual ~Callback(){};
virtual void onDispSyncEvent(nsecs_t when) = 0;
};
@@ -108,13 +106,12 @@
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
// (i.e. within a few hundred microseconds).
- status_t addEventListener(const char* name, nsecs_t phase,
- const sp<Callback>& callback);
+ status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
// removeEventListener removes an already-registered event callback. Once
// this method returns that callback will no longer be called by the
// DispSync object.
- status_t removeEventListener(const sp<Callback>& callback);
+ status_t removeEventListener(Callback* callback);
// computeNextRefresh computes when the next refresh is expected to begin.
// The periodOffset value can be used to move forward or backward; an
@@ -126,7 +123,6 @@
void dump(String8& result) const;
private:
-
void updateModelLocked();
void updateErrorLocked();
void resetErrorLocked();
@@ -174,8 +170,7 @@
// These member variables store information about the present fences used
// to validate the currently computed model.
- std::shared_ptr<FenceTime>
- mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
+ std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE};
size_t mPresentSampleOffset;
int mRefreshSkipCount;
@@ -193,8 +188,10 @@
// Ignore present (retire) fences if the device doesn't have support for the
// sync framework
bool mIgnorePresentFences;
+
+ std::unique_ptr<Callback> mZeroPhaseTracer;
};
-}
+} // namespace android
#endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index 02eea47..ac54059 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -14,50 +14,57 @@
* limitations under the License.
*/
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <cutils/sched_policy.h>
+#include <log/log.h>
+#include <system/thread_defs.h>
+
#include "EventControlThread.h"
-#include "SurfaceFlinger.h"
namespace android {
-EventControlThread::EventControlThread(const sp<SurfaceFlinger>& flinger):
- mFlinger(flinger),
- mVsyncEnabled(false) {
+EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
+ : mSetVSyncEnabled(function) {
+ pthread_setname_np(mThread.native_handle(), "EventControlThread");
+
+ pid_t tid = pthread_gettid_np(mThread.native_handle());
+ setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventControlThread::~EventControlThread() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mKeepRunning = false;
+ mCondition.notify_all();
+ }
+ mThread.join();
}
void EventControlThread::setVsyncEnabled(bool enabled) {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
mVsyncEnabled = enabled;
- mCond.signal();
+ mCondition.notify_all();
}
-bool EventControlThread::threadLoop() {
- enum class VsyncState {Unset, On, Off};
- auto currentVsyncState = VsyncState::Unset;
+// Unfortunately std::unique_lock gives warnings with -Wthread-safety
+void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+ auto keepRunning = true;
+ auto currentVsyncEnabled = false;
- while (true) {
- auto requestedVsyncState = VsyncState::On;
- {
- Mutex::Autolock lock(mMutex);
- requestedVsyncState =
- mVsyncEnabled ? VsyncState::On : VsyncState::Off;
- while (currentVsyncState == requestedVsyncState) {
- status_t err = mCond.wait(mMutex);
- if (err != NO_ERROR) {
- ALOGE("error waiting for new events: %s (%d)",
- strerror(-err), err);
- return false;
- }
- requestedVsyncState =
- mVsyncEnabled ? VsyncState::On : VsyncState::Off;
- }
- }
+ while (keepRunning) {
+ mSetVSyncEnabled(currentVsyncEnabled);
- bool enable = requestedVsyncState == VsyncState::On;
- mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable);
- currentVsyncState = requestedVsyncState;
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this, currentVsyncEnabled, keepRunning]() NO_THREAD_SAFETY_ANALYSIS {
+ return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
+ });
+ currentVsyncEnabled = mVsyncEnabled;
+ keepRunning = mKeepRunning;
}
-
- return false;
}
} // namespace android
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index 1b1ef75..321fb79 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -14,35 +14,41 @@
* limitations under the License.
*/
-#ifndef ANDROID_EVENTCONTROLTHREAD_H
-#define ANDROID_EVENTCONTROLTHREAD_H
+#pragma once
-#include <stddef.h>
+#include <cstddef>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
+#include <android-base/thread_annotations.h>
namespace android {
class SurfaceFlinger;
-class EventControlThread: public Thread {
+class EventControlThread {
public:
+ using SetVSyncEnabledFunction = std::function<void(bool)>;
- explicit EventControlThread(const sp<SurfaceFlinger>& flinger);
- virtual ~EventControlThread() {}
+ explicit EventControlThread(SetVSyncEnabledFunction function);
+ ~EventControlThread();
void setVsyncEnabled(bool enabled);
- virtual bool threadLoop();
private:
- sp<SurfaceFlinger> mFlinger;
- bool mVsyncEnabled;
+ void threadMain();
- Mutex mMutex;
- Condition mCond;
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+
+ const SetVSyncEnabledFunction mSetVSyncEnabled;
+ bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+ // Must be last so that everything is initialized before the thread starts.
+ std::thread mThread{&EventControlThread::threadMain, this};
};
-}
-
-#endif // ANDROID_EVENTCONTROLTHREAD_H
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 5c0e3b3..53d95e2 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -16,13 +16,17 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
#include <sys/types.h>
+#include <chrono>
+#include <cstdint>
#include <cutils/compiler.h>
+#include <cutils/sched_policy.h>
-#include <gui/IDisplayEventConnection.h>
#include <gui/DisplayEventReceiver.h>
+#include <gui/IDisplayEventConnection.h>
#include <utils/Errors.h>
#include <utils/String8.h>
@@ -31,109 +35,126 @@
#include "EventThread.h"
#include "SurfaceFlinger.h"
+using namespace std::chrono_literals;
+
// ---------------------------------------------------------------------------
+
namespace android {
+
// ---------------------------------------------------------------------------
-EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs)
- : mVSyncSource(src),
- mFlinger(flinger),
- mUseSoftwareVSync(false),
- mVsyncEnabled(false),
- mDebugVsyncEnabled(false),
- mInterceptVSyncs(interceptVSyncs) {
-
- for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- mVSyncEvent[i].header.id = 0;
- mVSyncEvent[i].header.timestamp = 0;
- mVSyncEvent[i].vsync.count = 0;
+EventThread::EventThread(VSyncSource* src, SurfaceFlinger& flinger, bool interceptVSyncs,
+ const char* threadName)
+ : mVSyncSource(src), mFlinger(flinger), mInterceptVSyncs(interceptVSyncs) {
+ for (auto& event : mVSyncEvent) {
+ event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ event.header.id = 0;
+ event.header.timestamp = 0;
+ event.vsync.count = 0;
}
+
+ mThread = std::thread(&EventThread::threadMain, this);
+
+ pthread_setname_np(mThread.native_handle(), threadName);
+
+ pid_t tid = pthread_gettid_np(mThread.native_handle());
+
+ // Use SCHED_FIFO to minimize jitter
+ constexpr int EVENT_THREAD_PRIORITY = 2;
+ struct sched_param param = {0};
+ param.sched_priority = EVENT_THREAD_PRIORITY;
+ if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO for EventThread");
+ }
+
+ set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventThread::~EventThread() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mKeepRunning = false;
+ mCondition.notify_all();
+ }
+ mThread.join();
}
void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
mVSyncSource->setPhaseOffset(phaseOffset);
}
-void EventThread::onFirstRef() {
- run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-}
-
sp<EventThread::Connection> EventThread::createEventConnection() const {
return new Connection(const_cast<EventThread*>(this));
}
status_t EventThread::registerDisplayEventConnection(
const sp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
mDisplayEventConnections.add(connection);
- mCondition.broadcast();
+ mCondition.notify_all();
return NO_ERROR;
}
-void EventThread::removeDisplayEventConnection(
- const wp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
+void EventThread::removeDisplayEventConnection(const wp<EventThread::Connection>& connection) {
+ std::lock_guard<std::mutex> lock(mMutex);
mDisplayEventConnections.remove(connection);
}
-void EventThread::setVsyncRate(uint32_t count,
- const sp<EventThread::Connection>& connection) {
+void EventThread::setVsyncRate(uint32_t count, const sp<EventThread::Connection>& connection) {
if (int32_t(count) >= 0) { // server must protect against bad params
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
const int32_t new_count = (count == 0) ? -1 : count;
if (connection->count != new_count) {
connection->count = new_count;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
}
-void EventThread::requestNextVsync(
- const sp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
+void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
+ std::lock_guard<std::mutex> lock(mMutex);
mFlinger.resyncWithRateLimit();
if (connection->count < 0) {
connection->count = 0;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
void EventThread::onScreenReleased() {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
if (!mUseSoftwareVSync) {
// disable reliance on h/w vsync
mUseSoftwareVSync = true;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
void EventThread::onScreenAcquired() {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
if (mUseSoftwareVSync) {
// resume use of h/w vsync
mUseSoftwareVSync = false;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
void EventThread::onVSyncEvent(nsecs_t timestamp) {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = timestamp;
mVSyncEvent[0].vsync.count++;
- mCondition.broadcast();
+ mCondition.notify_all();
}
void EventThread::onHotplugReceived(int type, bool connected) {
ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "received hotplug event for an invalid display (id=%d)", type);
+ "received hotplug event for an invalid display (id=%d)", type);
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
DisplayEventReceiver::Event event;
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
@@ -141,54 +162,54 @@
event.header.timestamp = systemTime();
event.hotplug.connected = connected;
mPendingEvents.add(event);
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
-bool EventThread::threadLoop() {
- DisplayEventReceiver::Event event;
- Vector< sp<EventThread::Connection> > signalConnections;
- signalConnections = waitForEvent(&event);
+void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mKeepRunning) {
+ DisplayEventReceiver::Event event;
+ Vector<sp<EventThread::Connection> > signalConnections;
+ signalConnections = waitForEventLocked(&lock, &event);
- // dispatch events to listeners...
- const size_t count = signalConnections.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<Connection>& conn(signalConnections[i]);
- // now see if we still need to report this event
- status_t err = conn->postEvent(event);
- if (err == -EAGAIN || err == -EWOULDBLOCK) {
- // The destination doesn't accept events anymore, it's probably
- // full. For now, we just drop the events on the floor.
- // FIXME: Note that some events cannot be dropped and would have
- // to be re-sent later.
- // Right-now we don't have the ability to do this.
- ALOGW("EventThread: dropping event (%08x) for connection %p",
- event.header.type, conn.get());
- } else if (err < 0) {
- // handle any other error on the pipe as fatal. the only
- // reasonable thing to do is to clean-up this connection.
- // The most common error we'll get here is -EPIPE.
- removeDisplayEventConnection(signalConnections[i]);
+ // dispatch events to listeners...
+ const size_t count = signalConnections.size();
+ for (size_t i = 0; i < count; i++) {
+ const sp<Connection>& conn(signalConnections[i]);
+ // now see if we still need to report this event
+ status_t err = conn->postEvent(event);
+ if (err == -EAGAIN || err == -EWOULDBLOCK) {
+ // The destination doesn't accept events anymore, it's probably
+ // full. For now, we just drop the events on the floor.
+ // FIXME: Note that some events cannot be dropped and would have
+ // to be re-sent later.
+ // Right-now we don't have the ability to do this.
+ ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
+ conn.get());
+ } else if (err < 0) {
+ // handle any other error on the pipe as fatal. the only
+ // reasonable thing to do is to clean-up this connection.
+ // The most common error we'll get here is -EPIPE.
+ removeDisplayEventConnection(signalConnections[i]);
+ }
}
}
- return true;
}
// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
-Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
- DisplayEventReceiver::Event* event)
-{
- Mutex::Autolock _l(mLock);
- Vector< sp<EventThread::Connection> > signalConnections;
+Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
+ std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+ Vector<sp<EventThread::Connection> > signalConnections;
- do {
+ while (signalConnections.isEmpty() && mKeepRunning) {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
- for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+ for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
@@ -214,7 +235,7 @@
// find out connections waiting for events
size_t count = mDisplayEventConnections.size();
- for (size_t i=0 ; i<count ; ) {
+ for (size_t i = 0; i < count;) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != nullptr) {
bool added = false;
@@ -231,7 +252,7 @@
signalConnections.add(connection);
added = true;
} else if (connection->count == 1 ||
- (vsyncCount % connection->count) == 0) {
+ (vsyncCount % connection->count) == 0) {
// continuous event, and time to report it
signalConnections.add(connection);
added = true;
@@ -285,8 +306,8 @@
// use a (long) timeout when waiting for h/w vsync, and
// generate fake events when necessary.
bool softwareSync = mUseSoftwareVSync;
- nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
- if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
+ auto timeout = softwareSync ? 16ms : 1000ms;
+ if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
@@ -302,10 +323,10 @@
// h/w vsync should be disabled, so this will wait until we
// get a new connection, or an existing connection becomes
// interested in receiving vsync again.
- mCondition.wait(mLock);
+ mCondition.wait(*lock);
}
}
- } while (signalConnections.isEmpty());
+ }
// here we're guaranteed to have a timestamp and some connections to signal
// (The connections might have dropped out of mDisplayEventConnections
@@ -318,7 +339,7 @@
// never enable h/w VSYNC when screen is off
if (!mVsyncEnabled) {
mVsyncEnabled = true;
- mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
+ mVSyncSource->setCallback(this);
mVSyncSource->setVSyncEnabled(true);
}
}
@@ -334,29 +355,23 @@
}
void EventThread::dump(String8& result) const {
- Mutex::Autolock _l(mLock);
- result.appendFormat("VSYNC state: %s\n",
- mDebugVsyncEnabled?"enabled":"disabled");
- result.appendFormat(" soft-vsync: %s\n",
- mUseSoftwareVSync?"enabled":"disabled");
+ std::lock_guard<std::mutex> lock(mMutex);
+ result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
+ result.appendFormat(" soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
result.appendFormat(" numListeners=%zu,\n events-delivered: %u\n",
- mDisplayEventConnections.size(),
- mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
- for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
- sp<Connection> connection =
- mDisplayEventConnections.itemAt(i).promote();
- result.appendFormat(" %p: count=%d\n",
- connection.get(), connection != nullptr ? connection->count : 0);
+ mDisplayEventConnections.size(),
+ mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+ for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
+ sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
+ result.appendFormat(" %p: count=%d\n", connection.get(),
+ connection != nullptr ? connection->count : 0);
}
}
// ---------------------------------------------------------------------------
-EventThread::Connection::Connection(
- const sp<EventThread>& eventThread)
- : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize)
-{
-}
+EventThread::Connection::Connection(EventThread* eventThread)
+ : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
EventThread::Connection::~Connection() {
// do nothing here -- clean-up will happen automatically
@@ -382,12 +397,11 @@
mEventThread->requestNextVsync(this);
}
-status_t EventThread::Connection::postEvent(
- const DisplayEventReceiver::Event& event) {
+status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 0823839..9ae8fb2 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -14,18 +14,21 @@
* limitations under the License.
*/
-#ifndef ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
-#define ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
-#include <private/gui/BitTube.h>
+#include <android-base/thread_annotations.h>
+
#include <gui/DisplayEventReceiver.h>
#include <gui/IDisplayEventConnection.h>
+#include <private/gui/BitTube.h>
#include <utils/Errors.h>
-#include <utils/threads.h>
#include <utils/SortedVector.h>
#include "DisplayDevice.h"
@@ -39,10 +42,9 @@
// ---------------------------------------------------------------------------
-
-class VSyncSource : public virtual RefBase {
+class VSyncSource {
public:
- class Callback: public virtual RefBase {
+ class Callback {
public:
virtual ~Callback() {}
virtual void onVSyncEvent(nsecs_t when) = 0;
@@ -50,14 +52,14 @@
virtual ~VSyncSource() {}
virtual void setVSyncEnabled(bool enable) = 0;
- virtual void setCallback(const sp<Callback>& callback) = 0;
+ virtual void setCallback(Callback* callback) = 0;
virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
};
-class EventThread : public Thread, private VSyncSource::Callback {
+class EventThread : private VSyncSource::Callback {
class Connection : public BnDisplayEventConnection {
public:
- explicit Connection(const sp<EventThread>& eventThread);
+ explicit Connection(EventThread* eventThread);
status_t postEvent(const DisplayEventReceiver::Event& event);
// count >= 1 : continuous event. count is the vsync rate
@@ -70,14 +72,15 @@
virtual void onFirstRef();
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t count) override;
- void requestNextVsync() override; // asynchronous
- sp<EventThread> const mEventThread;
+ void requestNextVsync() override; // asynchronous
+ EventThread* const mEventThread;
gui::BitTube mChannel;
};
public:
-
- EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs);
+ EventThread(VSyncSource* src, SurfaceFlinger& flinger, bool interceptVSyncs,
+ const char* threadName);
+ ~EventThread();
sp<Connection> createEventConnection() const;
status_t registerDisplayEventConnection(const sp<Connection>& connection);
@@ -94,47 +97,46 @@
// called when receiving a hotplug event
void onHotplugReceived(int type, bool connected);
- Vector< sp<EventThread::Connection> > waitForEvent(
- DisplayEventReceiver::Event* event);
-
void dump(String8& result) const;
void setPhaseOffset(nsecs_t phaseOffset);
private:
- virtual bool threadLoop();
- virtual void onFirstRef();
-
- virtual void onVSyncEvent(nsecs_t timestamp);
+ void threadMain();
+ Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
+ DisplayEventReceiver::Event* event)
+ REQUIRES(mMutex);
void removeDisplayEventConnection(const wp<Connection>& connection);
- void enableVSyncLocked();
- void disableVSyncLocked();
+ void enableVSyncLocked() REQUIRES(mMutex);
+ void disableVSyncLocked() REQUIRES(mMutex);
+
+ // Implements VSyncSource::Callback
+ void onVSyncEvent(nsecs_t timestamp) override;
// constants
- sp<VSyncSource> mVSyncSource;
+ VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
SurfaceFlinger& mFlinger;
- mutable Mutex mLock;
- mutable Condition mCondition;
+ std::thread mThread;
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
// protected by mLock
- SortedVector< wp<Connection> > mDisplayEventConnections;
- Vector< DisplayEventReceiver::Event > mPendingEvents;
- DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
- bool mUseSoftwareVSync;
- bool mVsyncEnabled;
+ SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
+ Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+ DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
+ mMutex);
+ bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
+ bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
// for debugging
- bool mDebugVsyncEnabled;
+ bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
- const bool mInterceptVSyncs;
+ const bool mInterceptVSyncs = false;
};
// ---------------------------------------------------------------------------
}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SURFACE_FLINGER_EVENT_THREAD_H */
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 0b1199c..5a6ff4d 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -14,32 +14,29 @@
* limitations under the License.
*/
-#include <stdint.h>
#include <errno.h>
+#include <stdint.h>
#include <sys/types.h>
#include <binder/IPCThreadState.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
#include <gui/IDisplayEventConnection.h>
-#include "MessageQueue.h"
#include "EventThread.h"
+#include "MessageQueue.h"
#include "SurfaceFlinger.h"
namespace android {
// ---------------------------------------------------------------------------
-MessageBase::MessageBase()
- : MessageHandler() {
-}
+MessageBase::MessageBase() : MessageHandler() {}
-MessageBase::~MessageBase() {
-}
+MessageBase::~MessageBase() {}
void MessageBase::handleMessage(const Message&) {
this->handler();
@@ -75,22 +72,17 @@
// ---------------------------------------------------------------------------
-MessageQueue::MessageQueue()
-{
-}
+MessageQueue::MessageQueue() {}
-MessageQueue::~MessageQueue() {
-}
+MessageQueue::~MessageQueue() {}
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
-{
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}
-void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
-{
+void MessageQueue::setEventThread(EventThread* eventThread) {
if (mEventThread == eventThread) {
return;
}
@@ -102,8 +94,8 @@
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEvents->stealReceiveChannel(&mEventTube);
- mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
- MessageQueue::cb_eventReceiver, this);
+ mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+ this);
}
void MessageQueue::waitMessage() {
@@ -128,9 +120,7 @@
} while (true);
}
-status_t MessageQueue::postMessage(
- const sp<MessageBase>& messageHandler, nsecs_t relTime)
-{
+status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
const Message dummyMessage;
if (relTime > 0) {
mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
@@ -140,7 +130,6 @@
return NO_ERROR;
}
-
void MessageQueue::invalidate() {
mEvents->requestNextVsync();
}
@@ -150,7 +139,7 @@
}
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
- MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+ MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
return queue->eventReceiver(fd, events);
}
@@ -158,7 +147,7 @@
ssize_t n;
DisplayEventReceiver::Event buffer[8];
while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
- for (int i=0 ; i<n ; i++) {
+ for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
mHandler->dispatchInvalidate();
break;
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 14f50bb..dcfc716 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -17,16 +17,16 @@
#ifndef ANDROID_MESSAGE_QUEUE_H
#define ANDROID_MESSAGE_QUEUE_H
-#include <stdint.h>
#include <errno.h>
+#include <stdint.h>
#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
#include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
-#include <private/gui/BitTube.h>
#include <gui/DisplayEventReceiver.h>
+#include <private/gui/BitTube.h>
#include "Barrier.h"
@@ -40,11 +40,10 @@
// ---------------------------------------------------------------------------
-class MessageBase : public MessageHandler
-{
+class MessageBase : public MessageHandler {
public:
MessageBase();
-
+
// return true if message has a handler
virtual bool handler() = 0;
@@ -79,15 +78,12 @@
class MessageQueue {
class Handler : public MessageHandler {
- enum {
- eventMaskInvalidate = 0x1,
- eventMaskRefresh = 0x2,
- eventMaskTransaction = 0x4
- };
+ enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
MessageQueue& mQueue;
int32_t mEventMask;
+
public:
- explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+ explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
virtual void handleMessage(const Message& message);
void dispatchRefresh();
void dispatchInvalidate();
@@ -97,28 +93,27 @@
sp<SurfaceFlinger> mFlinger;
sp<Looper> mLooper;
- sp<EventThread> mEventThread;
+ EventThread* mEventThread;
sp<IDisplayEventConnection> mEvents;
gui::BitTube mEventTube;
sp<Handler> mHandler;
-
static int cb_eventReceiver(int fd, int events, void* data);
int eventReceiver(int fd, int events);
public:
enum {
- INVALIDATE = 0,
- REFRESH = 1,
+ INVALIDATE = 0,
+ REFRESH = 1,
};
MessageQueue();
~MessageQueue();
void init(const sp<SurfaceFlinger>& flinger);
- void setEventThread(const sp<EventThread>& events);
+ void setEventThread(EventThread* events);
void waitMessage();
- status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
+ status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0);
// sends INVALIDATE message at next VSYNC
void invalidate();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d8740d9..1054c32 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -424,7 +424,7 @@
postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
}
-class DispSyncSource : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name) :
@@ -435,14 +435,13 @@
mVsyncEventLabel(String8::format("VSYNC-%s", name)),
mDispSync(dispSync),
mCallbackMutex(),
- mCallback(),
mVsyncMutex(),
mPhaseOffset(phaseOffset),
mEnabled(false) {}
- virtual ~DispSyncSource() {}
+ ~DispSyncSource() override = default;
- virtual void setVSyncEnabled(bool enable) {
+ void setVSyncEnabled(bool enable) override {
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
@@ -464,12 +463,12 @@
mEnabled = enable;
}
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ void setCallback(VSyncSource::Callback* callback) override{
Mutex::Autolock lock(mCallbackMutex);
mCallback = callback;
}
- virtual void setPhaseOffset(nsecs_t phaseOffset) {
+ void setPhaseOffset(nsecs_t phaseOffset) override {
Mutex::Autolock lock(mVsyncMutex);
// Normalize phaseOffset to [0, period)
@@ -506,7 +505,7 @@
private:
virtual void onDispSyncEvent(nsecs_t when) {
- sp<VSyncSource::Callback> callback;
+ VSyncSource::Callback* callback;
{
Mutex::Autolock lock(mCallbackMutex);
callback = mCallback;
@@ -533,37 +532,36 @@
DispSync* mDispSync;
Mutex mCallbackMutex; // Protects the following
- sp<VSyncSource::Callback> mCallback;
+ VSyncSource::Callback* mCallback = nullptr;
Mutex mVsyncMutex; // Protects the following
nsecs_t mPhaseOffset;
bool mEnabled;
};
-class InjectVSyncSource : public VSyncSource {
+class InjectVSyncSource final : public VSyncSource {
public:
- InjectVSyncSource() {}
+ InjectVSyncSource() = default;
+ ~InjectVSyncSource() override = default;
- virtual ~InjectVSyncSource() {}
-
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ void setCallback(VSyncSource::Callback* callback) override {
std::lock_guard<std::mutex> lock(mCallbackMutex);
mCallback = callback;
}
- virtual void onInjectSyncEvent(nsecs_t when) {
+ void onInjectSyncEvent(nsecs_t when) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
if (mCallback) {
mCallback->onVSyncEvent(when);
}
}
- virtual void setVSyncEnabled(bool) {}
- virtual void setPhaseOffset(nsecs_t) {}
+ void setVSyncEnabled(bool) override {}
+ void setPhaseOffset(nsecs_t) override {}
private:
std::mutex mCallbackMutex; // Protects the following
- sp<VSyncSource::Callback> mCallback;
+ VSyncSource::Callback* mCallback = nullptr;
};
// Do not call property_set on main thread which will be blocked by init
@@ -577,23 +575,16 @@
Mutex::Autolock _l(mStateLock);
// start the EventThread
- sp<VSyncSource> vsyncSrc =
- new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc, *this, false);
- sp<VSyncSource> sfVsyncSrc =
- new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
- mEventQueue.setEventThread(mSFEventThread);
- // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
- struct sched_param param = {0};
- param.sched_priority = 2;
- if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
- }
- if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for EventThread");
- }
+ mEventThreadSource = std::make_unique<DispSyncSource>(
+ &mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+ mEventThread = std::make_unique<EventThread>(
+ mEventThreadSource.get(), *this, false, "sfEventThread");
+ mSfEventThreadSource = std::make_unique<DispSyncSource>(
+ &mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = std::make_unique<EventThread>(
+ mSfEventThreadSource.get(), *this, true, "appEventThread");
+ mEventQueue.setEventThread(mSFEventThread.get());
// Get a RenderEngine for the given display / config (can't fail)
getBE().mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
@@ -636,8 +627,9 @@
}
}
- mEventControlThread = new EventControlThread(this);
- mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
+ mEventControlThread = std::make_unique<EventControlThread>([this](bool enabled) {
+ setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled);
+ });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -1072,13 +1064,14 @@
if (enable) {
ALOGV("VSync Injections enabled");
if (mVSyncInjector.get() == nullptr) {
- mVSyncInjector = new InjectVSyncSource();
- mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+ mVSyncInjector = std::make_unique<InjectVSyncSource>();
+ mInjectorEventThread = std::make_unique<EventThread>(
+ mVSyncInjector.get(), *this, false, "injEvThread");
}
- mEventQueue.setEventThread(mInjectorEventThread);
+ mEventQueue.setEventThread(mInjectorEventThread.get());
} else {
ALOGV("VSync Injections disabled");
- mEventQueue.setEventThread(mSFEventThread);
+ mEventQueue.setEventThread(mSFEventThread.get());
}
mInjectVSyncs = enable;
@@ -1101,7 +1094,8 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+ NO_THREAD_SAFETY_ANALYSIS {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
@@ -3567,7 +3561,8 @@
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
+ NO_THREAD_SAFETY_ANALYSIS {
String8 result;
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1349bec..19dd059 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -316,6 +316,9 @@
friend class BufferLayer;
friend class MonitoredProducer;
+ // For unit tests
+ friend class TestableSurfaceFlinger;
+
// This value is specified in number of frames. Log frame stats at most
// every half hour.
enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
@@ -716,11 +719,13 @@
// constant members (no synchronization needed for access)
nsecs_t mBootTime;
bool mGpuToCpuSupported;
- sp<EventThread> mEventThread;
- sp<EventThread> mSFEventThread;
- sp<EventThread> mInjectorEventThread;
- sp<InjectVSyncSource> mVSyncInjector;
- sp<EventControlThread> mEventControlThread;
+ std::unique_ptr<EventThread> mEventThread;
+ std::unique_ptr<EventThread> mSFEventThread;
+ std::unique_ptr<EventThread> mInjectorEventThread;
+ std::unique_ptr<VSyncSource> mEventThreadSource;
+ std::unique_ptr<VSyncSource> mSfEventThreadSource;
+ std::unique_ptr<InjectVSyncSource> mVSyncInjector;
+ std::unique_ptr<EventControlThread> mEventControlThread;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
// Can only accessed from the main thread, these members
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
new file mode 100644
index 0000000..7d3da32
--- /dev/null
+++ b/services/surfaceflinger/tests/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2018 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.
+
+cc_test {
+ name: "SurfaceFlinger_test",
+ defaults: ["surfaceflinger_defaults"],
+ tags: ["test"],
+ test_suites: ["device-tests"],
+ srcs: [
+ "Stress_test.cpp",
+ "SurfaceInterceptor_test.cpp",
+ "Transaction_test.cpp",
+ ],
+ data: ["SurfaceFlinger_test.filter"],
+ static_libs: [
+ "libtrace_proto",
+ ],
+ shared_libs: [
+ "libandroid",
+ "libbinder",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libgui",
+ "liblog",
+ "libprotobuf-cpp-full",
+ "libui",
+ "libutils",
+ ]
+
+}
+
+subdirs = [
+ "fakehwc",
+ "hwc2",
+ "unittests",
+ "vsync",
+ "waitforvsync",
+]
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
deleted file mode 100644
index 43e22a0..0000000
--- a/services/surfaceflinger/tests/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Build the unit tests,
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := SurfaceFlinger_test
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- Transaction_test.cpp \
- Stress_test.cpp \
- SurfaceInterceptor_test.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libEGL \
- libGLESv2 \
- libbinder \
- libcutils \
- libgui \
- libprotobuf-cpp-full \
- libui \
- libutils \
- libandroid \
- liblog
-
-LOCAL_STATIC_LIBRARIES := libtrace_proto
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-LOCAL_TEST_DATA = SurfaceFlinger_test.filter
-
-# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-# to integrate with auto-test framework.
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index eeb0f54..8e0ba83 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -1,5 +1,8 @@
cc_test {
name: "sffakehwc_test",
+ defaults: ["surfaceflinger_defaults"],
+ tags: ["test"],
+ test_suites: ["device-tests"],
srcs: [
"FakeComposerClient.cpp",
"FakeComposerService.cpp",
@@ -7,36 +10,31 @@
"SFFakeHwc_test.cpp"
],
shared_libs: [
- "libcutils",
- "libutils",
- "libbinder",
- "libui",
- "libgui",
- "liblog",
- "libnativewindow",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
- "libhwbinder",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libfmq",
+ "libgui",
"libhardware",
"libhidlbase",
- "libsync",
- "libfmq",
- "libbase",
"libhidltransport",
- "liblayers_proto"
+ "libhwbinder",
+ "liblayers_proto",
+ "liblog",
+ "libnativewindow",
+ "libsync",
+ "libui",
+ "libutils",
],
static_libs: [
"libhwcomposer-client",
- "libsurfaceflingerincludes",
"libtrace_proto",
"libgmock"
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
+ "libsurfaceflinger_headers",
],
- cppflags: [
- "-std=c++1z",
- ],
- tags: ["tests"],
- test_suites: ["device-tests"]
}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/hwc2/Android.bp b/services/surfaceflinger/tests/hwc2/Android.bp
new file mode 100644
index 0000000..e980522
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Android.bp
@@ -0,0 +1,56 @@
+// Copyright (C) 2018 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.
+
+cc_test {
+ name: "test-hwc2",
+ defaults: ["surfaceflinger_defaults"],
+ tags: ["test"],
+ cflags: [
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-DGL_GLEXT_PROTOTYPES",
+ "-fno-builtin",
+ "-fstack-protector-all",
+ "-g",
+ "-Wextra",
+ ],
+ srcs: [
+ "Hwc2Test.cpp",
+ "Hwc2TestProperties.cpp",
+ "Hwc2TestLayer.cpp",
+ "Hwc2TestLayers.cpp",
+ "Hwc2TestBuffer.cpp",
+ "Hwc2TestClientTarget.cpp",
+ "Hwc2TestVirtualDisplay.cpp",
+ "Hwc2TestPixelComparator.cpp",
+ ],
+ static_libs: [
+ "libadf",
+ "libadfhwc",
+ "libbase",
+ "libmath",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.common@1.0",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libgui",
+ "libhardware",
+ "libhwui",
+ "liblog",
+ "libsync",
+ "libui",
+ "libutils",
+ ],
+}
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk
deleted file mode 100644
index 010ac9c..0000000
--- a/services/surfaceflinger/tests/hwc2/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := test-hwc2
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS += \
- -fstack-protector-all \
- -g \
- -Wall -Wextra \
- -Werror \
- -fno-builtin \
- -DEGL_EGLEXT_PROTOTYPES \
- -DGL_GLEXT_PROTOTYPES
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libhardware \
- libEGL \
- libGLESv2 \
- libui \
- libgui \
- liblog \
- libsync \
- libhwui \
- android.hardware.graphics.common@1.0
-LOCAL_STATIC_LIBRARIES := \
- libbase \
- libadf \
- libadfhwc \
- libmath
-LOCAL_SRC_FILES := \
- Hwc2Test.cpp \
- Hwc2TestProperties.cpp \
- Hwc2TestLayer.cpp \
- Hwc2TestLayers.cpp \
- Hwc2TestBuffer.cpp \
- Hwc2TestClientTarget.cpp \
- Hwc2TestVirtualDisplay.cpp \
- Hwc2TestPixelComparator.cpp
-
-include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
new file mode 100644
index 0000000..72e0a0f
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2018 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.
+
+cc_test {
+ name: "libsurfaceflinger_unittest",
+ tags: ["test"],
+ defaults: ["libsurfaceflinger_defaults"],
+ test_suites: ["device-tests"],
+ srcs: [
+ ":libsurfaceflinger_sources",
+ "DisplayTransactionTest.cpp",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ header_libs: [
+ "libsurfaceflinger_headers",
+ ],
+}
diff --git a/services/surfaceflinger/tests/unittests/AndroidTest.xml b/services/surfaceflinger/tests/unittests/AndroidTest.xml
new file mode 100644
index 0000000..5e8b03b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for libsurfaceflinger_unittest">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libsurfaceflinger_unittest->/data/local/tmp/libsurfaceflinger_unittest" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libsurfaceflinger_unittest" />
+ </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
new file mode 100644
index 0000000..fc1b564
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "TestableSurfaceFlinger.h"
+
+namespace android {
+namespace {
+
+class DisplayTransactionTest : public testing::Test {
+protected:
+ DisplayTransactionTest();
+ ~DisplayTransactionTest() override;
+
+ void setupComposer(int virtualDisplayCount);
+ void setupPrimaryDisplay(int width, int height);
+
+ TestableSurfaceFlinger mFlinger;
+};
+
+DisplayTransactionTest::DisplayTransactionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+DisplayTransactionTest::~DisplayTransactionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+TEST_F(DisplayTransactionTest, PlaceholderTrivialTest) {
+ auto result = mFlinger.getDefaultDisplayDeviceLocked();
+ EXPECT_EQ(nullptr, result.get());
+
+ EXPECT_EQ(nullptr, mFlinger.mutableBuiltinDisplays()[0].get());
+ mFlinger.mutableBuiltinDisplays()[0] = new BBinder();
+ EXPECT_NE(nullptr, mFlinger.mutableBuiltinDisplays()[0].get());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
new file mode 100644
index 0000000..4aa59a5
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include "DisplayDevice.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+class TestableSurfaceFlinger {
+public:
+ // Extend this as needed for accessing SurfaceFlinger private (and public)
+ // functions.
+
+ /* ------------------------------------------------------------------------
+ * Forwarding for functions being tested
+ */
+ auto getDefaultDisplayDeviceLocked() const { return mFlinger->getDefaultDisplayDeviceLocked(); }
+
+ auto processDisplayChangesLocked() { return mFlinger->processDisplayChangesLocked(); }
+
+ /* ------------------------------------------------------------------------
+ * Read-write access to private data to set up preconditions and assert
+ * post-conditions.
+ */
+ auto& mutableBuiltinDisplays() { return mFlinger->mBuiltinDisplays; }
+
+ sp<SurfaceFlinger> mFlinger = new SurfaceFlinger();
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp
new file mode 100644
index 0000000..d04efda
--- /dev/null
+++ b/services/surfaceflinger/tests/vsync/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2018 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.
+
+cc_binary {
+ name: "test-vsync-events",
+ defaults: ["surfaceflinger_defaults"],
+ tags: ["test"],
+ srcs: [
+ "vsync.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libgui",
+ "libui",
+ "libutils",
+ ]
+
+}
diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk
deleted file mode 100644
index 8e41617..0000000
--- a/services/surfaceflinger/tests/vsync/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- vsync.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libbinder \
- libui \
- libgui
-
-LOCAL_MODULE:= test-vsync-events
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp
new file mode 100644
index 0000000..cb6d0fd
--- /dev/null
+++ b/services/surfaceflinger/tests/waitforvsync/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 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.
+
+cc_binary {
+ name: "test-waitforvsync",
+ cflags: [
+ "-Werror",
+ ],
+ srcs: [
+ "waitforvsync.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ ]
+}
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk
deleted file mode 100644
index 932d2be..0000000
--- a/services/surfaceflinger/tests/waitforvsync/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- waitforvsync.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
-
-LOCAL_MODULE:= test-waitforvsync
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/version-script32.txt b/services/surfaceflinger/version-script32.txt
new file mode 100644
index 0000000..2340785
--- /dev/null
+++ b/services/surfaceflinger/version-script32.txt
@@ -0,0 +1,12 @@
+{
+global:
+ EnsureFrontOfChain;
+ AddSpecialSignalHandlerFn;
+ RemoveSpecialSignalHandlerFn;
+ bsd_signal;
+ sigaction;
+ signal;
+ sigprocmask;
+local:
+ *;
+};
diff --git a/services/surfaceflinger/version-script64.txt b/services/surfaceflinger/version-script64.txt
new file mode 100644
index 0000000..acf3630
--- /dev/null
+++ b/services/surfaceflinger/version-script64.txt
@@ -0,0 +1,11 @@
+{
+global:
+ EnsureFrontOfChain;
+ AddSpecialSignalHandlerFn;
+ RemoveSpecialSignalHandlerFn;
+ sigaction;
+ signal;
+ sigprocmask;
+local:
+ *;
+};
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index 726e854..7404b94 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -97,6 +97,14 @@
return VK_SUCCESS;
}
+VKAPI_ATTR VkResult
+EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
+ uint32_t* count,
+ VkPhysicalDeviceGroupProperties* /*properties*/) {
+ *count = 0;
+ return VK_SUCCESS;
+}
+
VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
const char* name) {
if (strcmp(name, "vkCreateInstance") == 0)
@@ -108,6 +116,9 @@
EnumerateInstanceExtensionProperties);
if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+ if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ EnumeratePhysicalDeviceGroups);
if (strcmp(name, "vkGetInstanceProcAddr") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
// Per the spec, return NULL if instance is NULL.