/* * Copyright (C) 2022 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. */ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) // #define LOG_NDEBUG 0 // Uncomment to see HWC2 API calls in logcat #define LOG_TAG "drmhwc" #include #include "DrmHwcTwo.h" #include "backend/Backend.h" #include "utils/log.h" namespace android { /* Converts long __PRETTY_FUNCTION__ result, e.g.: * "int32_t android::LayerHook(hwc2_device_t *, hwc2_display_t, hwc2_layer_t," * "Args...) [HookType = HWC2::Error (android::HwcLayer::*)(const native_handle" * "*,int), func = &android::HwcLayer::SetLayerBuffer, Args = " * to the short "android::HwcLayer::SetLayerBuffer" for better logs readability */ static std::string GetFuncName(const char *pretty_function) { const std::string str(pretty_function); const char *start = "func = &"; auto p1 = str.find(start); p1 += strlen(start); auto p2 = str.find(',', p1); return str.substr(p1, p2 - p1); } struct Drmhwc2Device : hwc2_device { DrmHwcTwo drmhwctwo; }; static DrmHwcTwo *ToDrmHwcTwo(hwc2_device_t *dev) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast): return &static_cast(dev)->drmhwctwo; } template static hwc2_function_pointer_t ToHook(T function) { static_assert(std::is_same::value, "Incompatible fn pointer"); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): return reinterpret_cast(function); } template static T DeviceHook(hwc2_device_t *dev, Args... args) { ALOGV("Device hook: %s", GetFuncName(__PRETTY_FUNCTION__).c_str()); DrmHwcTwo *hwc = ToDrmHwcTwo(dev); const std::unique_lock lock(hwc->GetResMan().GetMainLock()); return static_cast(((*hwc).*func)(std::forward(args)...)); } template static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, Args... args) { ALOGV("Display #%" PRIu64 " hook: %s", display_handle, GetFuncName(__PRETTY_FUNCTION__).c_str()); DrmHwcTwo *hwc = ToDrmHwcTwo(dev); const std::unique_lock lock(hwc->GetResMan().GetMainLock()); auto *display = hwc->GetDisplay(display_handle); if (display == nullptr) return static_cast(HWC2::Error::BadDisplay); return static_cast((display->*func)(std::forward(args)...)); } template static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, hwc2_layer_t layer_handle, Args... args) { ALOGV("Display #%" PRIu64 " Layer: #%" PRIu64 " hook: %s", display_handle, layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str()); DrmHwcTwo *hwc = ToDrmHwcTwo(dev); const std::unique_lock lock(hwc->GetResMan().GetMainLock()); auto *display = hwc->GetDisplay(display_handle); if (display == nullptr) return static_cast(HWC2::Error::BadDisplay); HwcLayer *layer = display->get_layer(layer_handle); if (!layer) return static_cast(HWC2::Error::BadLayer); return static_cast((layer->*func)(std::forward(args)...)); } static int HookDevClose(hw_device_t *dev) { // NOLINTNEXTLINE (cppcoreguidelines-pro-type-reinterpret-cast): Safe auto *hwc2_dev = reinterpret_cast(dev); const std::unique_ptr ctx(ToDrmHwcTwo(hwc2_dev)); return 0; } static void HookDevGetCapabilities(hwc2_device_t * /*dev*/, uint32_t *out_count, int32_t * /*out_capabilities*/) { *out_count = 0; } static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/, int32_t descriptor) { auto func = static_cast(descriptor); switch (func) { // Device functions case HWC2::FunctionDescriptor::CreateVirtualDisplay: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::DestroyVirtualDisplay: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::Dump: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: return ToHook( DeviceHook); case HWC2::FunctionDescriptor::RegisterCallback: return ToHook( DeviceHook); // Display functions case HWC2::FunctionDescriptor::AcceptDisplayChanges: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::CreateLayer: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::DestroyLayer: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetActiveConfig: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetChangedCompositionTypes: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetClientTargetSupport: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetColorModes: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayAttribute: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayConfigs: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayName: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayRequests: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayType: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDozeSupport: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetHdrCapabilities: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetReleaseFences: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::PresentDisplay: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetActiveConfig: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetClientTarget: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetColorMode: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetColorTransform: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetOutputBuffer: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetPowerMode: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetVsyncEnabled: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::ValidateDisplay: return ToHook( DisplayHook); #if __ANDROID_API__ > 27 case HWC2::FunctionDescriptor::GetRenderIntents: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: return ToHook( DisplayHook); #endif #if __ANDROID_API__ > 28 case HWC2::FunctionDescriptor::GetDisplayIdentificationData: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayCapabilities: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetDisplayBrightness: return ToHook( DisplayHook); #endif /* __ANDROID_API__ > 28 */ #if __ANDROID_API__ > 29 case HWC2::FunctionDescriptor::GetDisplayConnectionType: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetAutoLowLatencyMode: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::GetSupportedContentTypes: return ToHook( DisplayHook); case HWC2::FunctionDescriptor::SetContentType: return ToHook( DisplayHook); #endif // Layer functions case HWC2::FunctionDescriptor::SetCursorPosition: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerBlendMode: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerBuffer: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerColor: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerCompositionType: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerDataspace: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerDisplayFrame: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerSidebandStream: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerSourceCrop: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerTransform: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerVisibleRegion: return ToHook( LayerHook); case HWC2::FunctionDescriptor::SetLayerZOrder: return ToHook( LayerHook); case HWC2::FunctionDescriptor::Invalid: default: return nullptr; } } static int HookDevOpen(const struct hw_module_t *module, const char *name, struct hw_device_t **dev) { if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) { ALOGE("Invalid module name- %s", name); return -EINVAL; } auto ctx = std::make_unique(); if (!ctx) { ALOGE("Failed to allocate DrmHwcTwo"); return -ENOMEM; } ctx->common.tag = HARDWARE_DEVICE_TAG; ctx->common.version = HWC_DEVICE_API_VERSION_2_0; ctx->common.close = HookDevClose; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) ctx->common.module = (hw_module_t *)module; ctx->getCapabilities = HookDevGetCapabilities; ctx->getFunction = HookDevGetFunction; *dev = &ctx.release()->common; return 0; } } // namespace android // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static struct hw_module_methods_t hwc2_module_methods = { .open = android::HookDevOpen, }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0), .id = HWC_HARDWARE_MODULE_ID, .name = "DrmHwcTwo module", .author = "The Android Open Source Project", .methods = &hwc2_module_methods, .dso = nullptr, .reserved = {0}, };