blob: 0971b4da64e318bb733c5286e46bd652d35c8a08 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/screen_ai/screen_ai_library_wrapper_impl.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "components/crash/core/common/crash_key.h"
#include "ui/accessibility/accessibility_features.h"
namespace screen_ai {
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
void HandleLibraryLogging(int severity, const char* message) {
switch (severity) {
case logging::LOGGING_VERBOSE:
case logging::LOGGING_INFO:
VLOG(2) << message;
break;
case logging::LOGGING_WARNING:
VLOG(1) << message;
break;
case logging::LOGGING_ERROR:
case logging::LOGGING_FATAL:
VLOG(0) << message;
break;
}
}
#endif
} // namespace
ScreenAILibraryWrapperImpl::ScreenAILibraryWrapperImpl() = default;
template <typename T>
bool ScreenAILibraryWrapperImpl::LoadFunction(T& function_variable,
const char* function_name) {
function_variable =
reinterpret_cast<T>(library_.GetFunctionPointer(function_name));
if (function_variable == nullptr) {
VLOG(0) << "Could not load function: " << function_name;
return false;
}
return true;
}
bool ScreenAILibraryWrapperImpl::Load(const base::FilePath& library_path) {
library_ = base::ScopedNativeLibrary(library_path);
#if BUILDFLAG(IS_WIN)
DWORD error = library_.GetError()->code;
base::UmaHistogramSparse(
"Accessibility.ScreenAI.LibraryLoadDetailedResultOnWindows",
static_cast<int>(error));
if (error != ERROR_SUCCESS) {
VLOG(0) << "Library load error: " << library_.GetError()->code;
return false;
}
#else
if (!library_.GetError()->message.empty()) {
VLOG(0) << "Library load error: " << library_.GetError()->message;
return false;
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!LoadFunction(set_logger_, "SetLogger")) {
return false;
}
#endif
// General functions.
if (!LoadFunction(get_library_version_, "GetLibraryVersion") ||
!LoadFunction(get_library_version_, "GetLibraryVersion") ||
!LoadFunction(enable_debug_mode_, "EnableDebugMode") ||
!LoadFunction(set_file_content_functions_, "SetFileContentFunctions") ||
!LoadFunction(free_library_allocated_int32_array_,
"FreeLibraryAllocatedInt32Array") ||
!LoadFunction(free_library_allocated_char_array_,
"FreeLibraryAllocatedCharArray")) {
return false;
}
if (!LoadFunction(init_ocr_, "InitOCRUsingCallback") ||
!LoadFunction(perform_ocr_, "PerformOCR")) {
return false;
}
// Main Content Extraction functions.
if (!LoadFunction(init_main_content_extraction_,
"InitMainContentExtractionUsingCallback") ||
!LoadFunction(extract_main_content_, "ExtractMainContent")) {
return false;
}
return true;
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapperImpl::ScreenAILibraryWrapperImpl::SetLogger() {
CHECK(set_logger_);
set_logger_(&HandleLibraryLogging);
}
#endif
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapperImpl::GetLibraryVersion(uint32_t& major,
uint32_t& minor) {
CHECK(get_library_version_);
get_library_version_(major, minor);
}
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapperImpl::SetFileContentFunctions(
uint32_t (*get_file_content_size)(const char* /*relative_file_path*/),
void (*get_file_content)(const char* /*relative_file_path*/,
uint32_t /*buffer_size*/,
char* /*buffer*/)) {
CHECK(set_file_content_functions_);
set_file_content_functions_(get_file_content_size, get_file_content);
}
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapperImpl::EnableDebugMode() {
CHECK(enable_debug_mode_);
enable_debug_mode_();
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapperImpl::InitOCR() {
SCOPED_UMA_HISTOGRAM_TIMER(
"Accessibility.ScreenAI.OCR.InitializationLatency");
CHECK(init_ocr_);
return init_ocr_();
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapperImpl::InitMainContentExtraction() {
SCOPED_UMA_HISTOGRAM_TIMER(
"Accessibility.ScreenAI.MainContentExtraction.InitializationLatency");
CHECK(init_main_content_extraction_);
return init_main_content_extraction_();
}
NO_SANITIZE("cfi-icall")
std::optional<chrome_screen_ai::VisualAnnotation>
ScreenAILibraryWrapperImpl::PerformOcr(const SkBitmap& image) {
CHECK(perform_ocr_);
CHECK(free_library_allocated_char_array_);
// Report image specifications in case the call crashes.
static crash_reporter::CrashKeyString<50> image_info("ocr_image_info");
image_info.Set(base::StringPrintf(
"W:%5i, H:%5i, CT:%2i, BPP:%2i, RB:%5zu, DN:%i", image.width(),
image.height(), static_cast<int>(image.colorType()),
image.bytesPerPixel(), image.rowBytes(), image.drawsNothing()));
std::optional<chrome_screen_ai::VisualAnnotation> annotation_proto;
uint32_t annotation_proto_length = 0;
// Memory allocated in `library_buffer` should be release only using
// `free_library_allocated_char_array_` function. Using unique_ptr custom
// deleter results in crash on Linux official build.
std::unique_ptr<char> library_buffer(
perform_ocr_(image, annotation_proto_length));
if (!library_buffer) {
return annotation_proto;
}
annotation_proto = chrome_screen_ai::VisualAnnotation();
if (!annotation_proto->ParseFromArray(library_buffer.get(),
annotation_proto_length)) {
annotation_proto.reset();
}
free_library_allocated_char_array_(library_buffer.release());
return annotation_proto;
}
NO_SANITIZE("cfi-icall")
std::optional<std::vector<int32_t>>
ScreenAILibraryWrapperImpl::ExtractMainContent(
const std::string& serialized_view_hierarchy) {
CHECK(extract_main_content_);
CHECK(free_library_allocated_int32_array_);
std::optional<std::vector<int32_t>> node_ids;
uint32_t nodes_count = 0;
// Memory allocated in `library_buffer` should be release only using
// `free_library_allocated_int32_array_` function.
std::unique_ptr<int32_t> library_buffer(
extract_main_content_(serialized_view_hierarchy.data(),
serialized_view_hierarchy.length(), nodes_count));
if (!library_buffer) {
return node_ids;
}
node_ids = std::vector<int32_t>(nodes_count);
if (nodes_count != 0) {
memcpy(node_ids->data(), library_buffer.get(),
nodes_count * sizeof(int32_t));
}
free_library_allocated_int32_array_(library_buffer.release());
return node_ids;
}
} // namespace screen_ai