Add a C-api for retrieving display info.

As HWUI will need to depend on ABI-stable interfaces moving forward, we
need such an interface against SurfaceComposer for retrieving display
metadata.

This CL won't contain a map file to stabilize the ABI yet, as I expect
that there will be some flux due to refresh rate apis.

Bug: 136263392
Test: builds
Change-Id: I7227e2e72789d36a21534840eac88817135251c3
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
new file mode 100644
index 0000000..6665635
--- /dev/null
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apex/display.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/GraphicTypes.h>
+
+#include <algorithm>
+#include <optional>
+#include <type_traits>
+#include <vector>
+
+namespace android::display::impl {
+
+/**
+ * Implementation of ADisplayConfig
+ */
+struct DisplayConfigImpl {
+    /**
+     * The width in pixels of the display configuration.
+     */
+    int32_t width{0};
+
+    /**
+     * The height in pixels of the display configuration.
+     */
+
+    int32_t height{0};
+
+    /**
+     * The display density.
+     */
+    float density{0};
+
+    /**
+     * The refresh rate of the display configuration, in frames per second.
+     */
+    float fps{0.0};
+
+    /**
+     * The vsync offset at which surfaceflinger runs, in nanoseconds.
+     */
+    int64_t sfOffset{0};
+
+    /**
+     * The vsync offset at which applications run, in nanoseconds.
+     */
+    int64_t appOffset{0};
+};
+
+// DisplayConfigImpl allocation is not managed through C++ memory apis, so
+// preventing calling the destructor here.
+static_assert(std::is_trivially_destructible<DisplayConfigImpl>::value);
+
+/**
+ * Implementation of ADisplay
+ */
+struct DisplayImpl {
+    /**
+     * A physical display ID, unique to this display.
+     */
+    PhysicalDisplayId id;
+
+    /**
+     * The type of the display, i.e. whether it is an internal or external
+     * display.
+     */
+    ADisplayType type;
+
+    /**
+     * Number of supported configs
+     */
+    size_t numConfigs;
+
+    /**
+     * Set of supported configs by this display.
+     */
+    DisplayConfigImpl* configs;
+};
+
+// DisplayImpl allocation is not managed through C++ memory apis, so
+// preventing calling the destructor here.
+static_assert(std::is_trivially_destructible<DisplayImpl>::value);
+
+} // namespace android::display::impl
+
+using namespace android;
+using namespace android::display::impl;
+
+#define CHECK_NOT_NULL(name) \
+    LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+namespace {
+sp<IBinder> getToken(ADisplay* display) {
+    DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+    return SurfaceComposerClient::getPhysicalDisplayToken(impl->id);
+}
+
+int64_t computeSfOffset(const DisplayInfo& info) {
+    // This should probably be part of the config instead of extrapolated from
+    // the presentation deadline and fudged here, but the way the math works out
+    // here we do get the right offset.
+    return static_cast<int64_t>((1000000000 / info.fps) - info.presentationDeadline + 1000000);
+}
+} // namespace
+
+int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
+    const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
+    const size_t size = ids.size();
+    if (size == 0) {
+        return NO_INIT;
+    }
+
+    std::vector<DisplayConfigImpl> configsPerDisplay[size];
+    int numConfigs = 0;
+    for (int i = 0; i < size; ++i) {
+        const sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]);
+        Vector<DisplayInfo> configs;
+        const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+        if (status != OK) {
+            return status;
+        }
+        if (configs.empty()) {
+            return NO_INIT;
+        }
+
+        numConfigs += configs.size();
+        configsPerDisplay[i].reserve(configs.size());
+        for (int j = 0; j < configs.size(); ++j) {
+            const DisplayInfo config = configs[j];
+            configsPerDisplay[i].emplace_back(
+                    DisplayConfigImpl{static_cast<int32_t>(config.w),
+                                      static_cast<int32_t>(config.h), config.density, config.fps,
+                                      computeSfOffset(config), config.appVsyncOffset});
+        }
+    }
+
+    const std::optional<PhysicalDisplayId> internalId =
+            SurfaceComposerClient::getInternalDisplayId();
+
+    // Here we allocate all our required memory in one block. The layout is as
+    // follows:
+    // ------------------------------------------------------------
+    // | DisplayImpl pointers | DisplayImpls | DisplayConfigImpls |
+    // ------------------------------------------------------------
+    //
+    // The caller will be given a DisplayImpl** which points to the beginning of
+    // the block of DisplayImpl pointers.
+    // Each DisplayImpl* points to a DisplayImpl in the second block.
+    // Each DisplayImpl contains a DisplayConfigImpl*, which points to a
+    // contiguous block of DisplayConfigImpls specific to that display.
+    DisplayImpl** const impls = reinterpret_cast<DisplayImpl**>(
+            malloc((sizeof(DisplayImpl) + sizeof(DisplayImpl*)) * size +
+                   sizeof(DisplayConfigImpl) * numConfigs));
+    DisplayImpl* const displayData = reinterpret_cast<DisplayImpl*>(impls + size);
+    DisplayConfigImpl* configData = reinterpret_cast<DisplayConfigImpl*>(displayData + size);
+
+    for (size_t i = 0; i < size; ++i) {
+        const PhysicalDisplayId id = ids[i];
+        const ADisplayType type = (internalId == id) ? ADisplayType::DISPLAY_TYPE_INTERNAL
+                                                     : ADisplayType::DISPLAY_TYPE_EXTERNAL;
+        const std::vector<DisplayConfigImpl>& configs = configsPerDisplay[i];
+        memcpy(configData, configs.data(), sizeof(DisplayConfigImpl) * configs.size());
+
+        displayData[i] = DisplayImpl{id, type, configs.size(), configData};
+        impls[i] = displayData + i;
+        // Advance the configData pointer so that future configs are written to
+        // the correct display.
+        configData += configs.size();
+    }
+
+    *outDisplays = reinterpret_cast<ADisplay**>(impls);
+    return size;
+}
+
+void ADisplay_release(ADisplay** displays) {
+    if (displays == nullptr) {
+        return;
+    }
+    free(displays);
+}
+
+float ADisplay_getMaxSupportedFps(ADisplay* display) {
+    CHECK_NOT_NULL(display);
+    DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+    float maxFps = 0.0;
+    for (int i = 0; i < impl->numConfigs; ++i) {
+        maxFps = std::max(maxFps, impl->configs[i].fps);
+    }
+    return maxFps;
+}
+
+ADisplayType ADisplay_getDisplayType(ADisplay* display) {
+    CHECK_NOT_NULL(display);
+
+    return reinterpret_cast<DisplayImpl*>(display)->type;
+}
+
+int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) {
+    CHECK_NOT_NULL(display);
+
+    sp<IBinder> token = getToken(display);
+    const int index = SurfaceComposerClient::getActiveConfig(token);
+    if (index < 0) {
+        return index;
+    }
+
+    DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+
+    *outConfig = reinterpret_cast<ADisplayConfig*>(impl->configs + index);
+    return OK;
+}
+
+float ADisplayConfig_getDensity(ADisplayConfig* config) {
+    CHECK_NOT_NULL(config);
+
+    return reinterpret_cast<DisplayConfigImpl*>(config)->density;
+}
+
+int32_t ADisplayConfig_getWidth(ADisplayConfig* config) {
+    CHECK_NOT_NULL(config);
+
+    return reinterpret_cast<DisplayConfigImpl*>(config)->width;
+}
+
+int32_t ADisplayConfig_getHeight(ADisplayConfig* config) {
+    CHECK_NOT_NULL(config);
+
+    return reinterpret_cast<DisplayConfigImpl*>(config)->height;
+}
+
+float ADisplayConfig_getFps(ADisplayConfig* config) {
+    CHECK_NOT_NULL(config);
+
+    return reinterpret_cast<DisplayConfigImpl*>(config)->fps;
+}
+
+int64_t ADisplayConfig_getCompositorOffsetNanos(ADisplayConfig* config) {
+    CHECK_NOT_NULL(config);
+
+    return reinterpret_cast<DisplayConfigImpl*>(config)->sfOffset;
+}
+
+int64_t ADisplayConfig_getAppVsyncOffsetNanos(ADisplayConfig* config) {
+    CHECK_NOT_NULL(config);
+
+    return reinterpret_cast<DisplayConfigImpl*>(config)->appOffset;
+}
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
new file mode 100644
index 0000000..66ebdfd
--- /dev/null
+++ b/libs/nativedisplay/Android.bp
@@ -0,0 +1,50 @@
+// Copyright 2019 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_library_headers {
+    name: "libnativedisplay_headers",
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libnativedisplay",
+    export_include_dirs: [
+        "include",
+    ],
+
+    clang: true,
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-enum-compare",
+        "-Wno-unused-function",
+    ],
+
+    srcs: [
+        "ADisplay.cpp",
+    ],
+
+    shared_libs: [
+        "libgui",
+        "liblog",
+        "libui",
+        "libutils",
+    ],
+
+    header_libs: [
+        "libnativedisplay_headers",
+    ],
+
+}
diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h
new file mode 100644
index 0000000..7af452a
--- /dev/null
+++ b/libs/nativedisplay/include/apex/display.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2019 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 <inttypes.h>
+
+__BEGIN_DECLS
+
+/**
+ * Opaque handle for a native display
+ */
+typedef struct ADisplay ADisplay;
+
+/**
+ * Enum describing the possible types of a display
+ */
+enum ADisplayType {
+    /**
+     * A display that is the internal, or "primary" display for a device.
+     */
+    DISPLAY_TYPE_INTERNAL = 0,
+
+    /**
+     * A display that is externally connected for a device.
+     */
+    DISPLAY_TYPE_EXTERNAL = 1,
+};
+
+/**
+ * Opaque handle for display metadata
+ */
+typedef struct ADisplayConfig ADisplayConfig;
+
+/**
+ * Acquires a list of display handles. Memory is allocated for the list and is
+ * owned by the caller. The caller is responsible for freeing this memory by
+ * calling ADisplayList_release.
+ *
+ * Returns the size of the returned list on success.
+ * Returns -errno on error.
+ */
+int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays);
+
+/**
+ * Releases a list of display handles created by
+ * ADisplayList_acquirePhysicalDisplays.
+ */
+void ADisplay_release(ADisplay** displays);
+
+/**
+ * Queries the maximum supported fps for the given display.
+ */
+float ADisplay_getMaxSupportedFps(ADisplay* display);
+
+/**
+ * Queries the display's type.
+ */
+ADisplayType ADisplay_getDisplayType(ADisplay* display);
+
+/**
+ * Gets the current display configuration for the given display.
+ *
+ * Memory is *not* allocated for the caller. As such, the returned output
+ * configuration's lifetime will not be longer than the ADisplay* passed to this
+ * function - if ADisplay_release is called destroying the ADisplay object then
+ * it is invalid to access the ADisplayConfig returned here.
+ *
+ * Note that the current display configuration can change. Listening to updates
+ * to the current display configuration should be done via Choreographer. If
+ * such an update is observed, then this method should be recalled to get the
+ * new current configuration.
+ *
+ * Returns OK on success, -errno on failure.
+ */
+int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig);
+
+/**
+ * Queries the density for a given display configuration.
+ */
+float ADisplayConfig_getDensity(ADisplayConfig* config);
+
+/**
+ * Queries the width in pixels for a given display configuration.
+ */
+int32_t ADisplayConfig_getWidth(ADisplayConfig* config);
+
+/**
+ * Queries the height in pixels for a given display configuration.
+ */
+int32_t ADisplayConfig_getHeight(ADisplayConfig* config);
+
+/**
+ * Queries the display refresh rate for a given display configuration.
+ */
+float ADisplayConfig_getFps(ADisplayConfig* config);
+
+/**
+ * Queries the vsync offset from which the system compositor is scheduled to
+ * run. If a vsync occurs at time T, and the compositor runs at time T + S, then
+ * this returns S in nanoseconds.
+ */
+int64_t ADisplayConfig_getCompositorOffsetNanos(ADisplayConfig* config);
+
+/**
+ * Queries the vsync offset from which applications are scheduled to run. If a
+ * vsync occurs at time T, and applications run at time T + S, then this returns
+ * S in nanoseconds.
+ */
+int64_t ADisplayConfig_getAppVsyncOffsetNanos(ADisplayConfig* config);
+
+__END_DECLS