SF: Introduce libsurfaceflinger_unittest

This is meant to be a framework for running function-level unit tests
against the various SurfaceFlinger classes.

The point of this patch is to set up the test framework, as well as
demonstrate a pattern to be used to allow private implementation
functions to be tested.

Note that this patch configures the base surfaceflinger code to now use
ThinLTO, and enables -fwhole-program-vtables. This is done as ThinLTO
with that option will perform a devirtualization pass, turning virtual
function calls back into non-virtual function calls (and possibly even
inlining the call) when it detects that there is only one possible
implementation being called. The cost is a slight increase in build time
(similar to -O2), but is still much less than the original LTO.

Even here that LTO pass does something to the surfaceflinger binary,
reducing the file size by 4Kb.

Test: libsurfaceflinger_unittest passes on Pixel XL
Test: atest libsurfaceflinger_unittest runs the new test
Bug: None
Change-Id: I362ec1fcf1a909c4d6769710d8d8a6b0b158600d
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index b1a3017..9f3189a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -17,7 +17,6 @@
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
     ],
-    logtags: ["EventLog/EventLogTags.logtags"],
     shared_libs: [
         "android.frameworks.vr.composer@1.0",
         "android.hardware.configstore-utils",
@@ -131,10 +130,17 @@
     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 {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1349bec..bde1a8e 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 };
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 04c62b3..7d3da32 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -44,6 +44,7 @@
 subdirs = [
     "fakehwc",
     "hwc2",
+    "unittests",
     "vsync",
     "waitforvsync",
 ]
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