diff options
author | Roger Zanoni <rzanoni@igalia.com> | 2023-06-23 14:06:20 +0200 |
---|---|---|
committer | Roger Zanoni <rzanoni@igalia.com> | 2023-07-18 15:28:52 +0200 |
commit | 1ad25b9039ef910dc444e50fd43245c31d9bcae9 (patch) | |
tree | e29b75b0abcaddd0f16a7f238be7873fe0530b56 /recipes-wam/wam/files/0001-agl-cef-Snapshot-with-all-patches-needed-to-enable-w.patch | |
parent | 7a7c0e1f4c62ab976dfd2a58d33ed93d62c587d3 (diff) |
[wam][cef] Make it possible to use cef as a backend
This changes enables switching between the chromium and cef backends on
wam by passing the agl-cef feature to the agl-setup script.
Bug-AGL: SPEC-3872
Signed-off-by: Roger Zanoni <rzanoni@igalia.com>
Change-Id: Ib5b4b139789ec8303fef0a210a7e8f2f724d0c00
Diffstat (limited to 'recipes-wam/wam/files/0001-agl-cef-Snapshot-with-all-patches-needed-to-enable-w.patch')
-rw-r--r-- | recipes-wam/wam/files/0001-agl-cef-Snapshot-with-all-patches-needed-to-enable-w.patch | 3702 |
1 files changed, 3702 insertions, 0 deletions
diff --git a/recipes-wam/wam/files/0001-agl-cef-Snapshot-with-all-patches-needed-to-enable-w.patch b/recipes-wam/wam/files/0001-agl-cef-Snapshot-with-all-patches-needed-to-enable-w.patch new file mode 100644 index 000000000..65c2e7c66 --- /dev/null +++ b/recipes-wam/wam/files/0001-agl-cef-Snapshot-with-all-patches-needed-to-enable-w.patch @@ -0,0 +1,3702 @@ +From 54da26083a7a08b73fe617b683c3f3c8c895c4a2 Mon Sep 17 00:00:00 2001 +From: Jose Dapena Paz <jdapena@igalia.com> +Date: Fri, 9 Jun 2023 14:08:08 +0200 +Subject: [PATCH] [agl][cef] Snapshot with all patches needed to enable wam-cef + +--- + CMakeLists.txt | 18 +- + src/CMakeLists.txt | 58 ++- + src/agl-cef/CMakeLists.txt | 54 +++ + src/agl-cef/plugin/CMakeLists.txt | 59 +++ + src/agl-cef/plugin/agl_cef_context.cc | 4 + + src/agl-cef/plugin/agl_cef_context.h | 42 ++ + src/agl-cef/plugin/background_cef_app.cc | 33 ++ + src/agl-cef/plugin/background_cef_app.h | 20 + + src/agl-cef/plugin/homescreen_cef_app.cc | 25 ++ + src/agl-cef/plugin/homescreen_cef_app.h | 15 + + src/agl-cef/plugin/regular_cef_app.cc | 11 + + src/agl-cef/plugin/regular_cef_app.h | 12 + + src/agl-cef/plugin/web_app_factory_agl_cef.cc | 49 +++ + src/agl-cef/plugin/web_app_factory_agl_cef.h | 23 ++ + src/agl-cef/web_runtime_agl_cef.cc | 63 +++ + src/agl-cef/web_runtime_agl_cef.h | 11 + + src/agl/web_runtime_agl.cc | 16 +- + src/agl/web_runtime_agl.h | 20 +- + src/cef/cli/CMakeLists.txt | 17 + + src/cef/cli/wam_cli.cc | 171 ++++++++ + src/cef/device_info_cef.cc | 104 +++++ + src/cef/device_info_cef.h | 38 ++ + src/cef/handlers/wam_cef_browser_handler.cc | 31 ++ + src/cef/handlers/wam_cef_browser_handler.h | 23 ++ + src/cef/handlers/wam_cef_client.cc | 39 ++ + src/cef/handlers/wam_cef_client.h | 31 ++ + src/cef/handlers/wam_cef_render_handler.cc | 135 +++++++ + src/cef/handlers/wam_cef_render_handler.h | 54 +++ + src/cef/platform_module_factory_cef.cc | 31 ++ + src/cef/platform_module_factory_cef.h | 27 ++ + src/cef/plugin/web_app_cef.cc | 172 ++++++++ + src/cef/plugin/web_app_cef.h | 95 +++++ + src/cef/plugin/web_page_cef.cc | 48 +++ + src/cef/plugin/web_page_cef.h | 69 ++++ + src/cef/service/CMakeLists.txt | 64 +++ + src/cef/service/applauncher.proto | 50 +++ + src/cef/service/applauncher_client_grpc.cc | 58 +++ + src/cef/service/applauncher_client_grpc.h | 24 ++ + src/cef/service/wam_ipc.proto | 22 + + .../service/web_app_manager_client_grpc.cc | 42 ++ + src/cef/service/web_app_manager_client_grpc.h | 23 ++ + .../service/web_app_manager_service_grpc.cc | 382 ++++++++++++++++++ + .../service/web_app_manager_service_grpc.h | 85 ++++ + src/core/CMakeLists.txt | 4 + + src/core/application_description.cc | 37 ++ + src/core/application_installation_handler.h | 12 + + .../application_installation_handler_stub.cc | 4 + + src/core/memory_pressure_level.h | 6 + + src/core/web_app_manager.cc | 29 +- + src/core/web_app_manager.h | 4 +- + src/core/web_app_manager_service.cc | 4 +- + src/core/web_app_manager_service.h | 3 +- + src/core/web_page_base.h | 6 +- + src/core/web_process_manager.h | 1 + + src/core/web_runtime.h | 3 +- + src/desktop/CMakeLists.txt | 100 +++++ + src/desktop/README.md | 102 +++++ + src/desktop/web_runtime_desktop.cc | 28 ++ + src/desktop/web_runtime_desktop.h | 11 + + src/platform/CMakeLists.txt | 23 +- + src/platform/web_app_window.h | 6 +- + src/util/log_msg_id.h | 2 + + src/util/timer.h | 4 +- + src/wam_main.cc | 4 +- + src/webos/web_app_manager_service_luna.cc | 2 + + src/webos/web_runtime_webos.cc | 2 +- + src/webos/web_runtime_webos.h | 2 +- + 67 files changed, 2693 insertions(+), 74 deletions(-) + create mode 100644 src/agl-cef/CMakeLists.txt + create mode 100644 src/agl-cef/plugin/CMakeLists.txt + create mode 100644 src/agl-cef/plugin/agl_cef_context.cc + create mode 100644 src/agl-cef/plugin/agl_cef_context.h + create mode 100644 src/agl-cef/plugin/background_cef_app.cc + create mode 100644 src/agl-cef/plugin/background_cef_app.h + create mode 100644 src/agl-cef/plugin/homescreen_cef_app.cc + create mode 100644 src/agl-cef/plugin/homescreen_cef_app.h + create mode 100644 src/agl-cef/plugin/regular_cef_app.cc + create mode 100644 src/agl-cef/plugin/regular_cef_app.h + create mode 100644 src/agl-cef/plugin/web_app_factory_agl_cef.cc + create mode 100644 src/agl-cef/plugin/web_app_factory_agl_cef.h + create mode 100644 src/agl-cef/web_runtime_agl_cef.cc + create mode 100644 src/agl-cef/web_runtime_agl_cef.h + create mode 100644 src/cef/cli/CMakeLists.txt + create mode 100644 src/cef/cli/wam_cli.cc + create mode 100644 src/cef/device_info_cef.cc + create mode 100644 src/cef/device_info_cef.h + create mode 100644 src/cef/handlers/wam_cef_browser_handler.cc + create mode 100644 src/cef/handlers/wam_cef_browser_handler.h + create mode 100644 src/cef/handlers/wam_cef_client.cc + create mode 100644 src/cef/handlers/wam_cef_client.h + create mode 100644 src/cef/handlers/wam_cef_render_handler.cc + create mode 100644 src/cef/handlers/wam_cef_render_handler.h + create mode 100644 src/cef/platform_module_factory_cef.cc + create mode 100644 src/cef/platform_module_factory_cef.h + create mode 100644 src/cef/plugin/web_app_cef.cc + create mode 100644 src/cef/plugin/web_app_cef.h + create mode 100644 src/cef/plugin/web_page_cef.cc + create mode 100644 src/cef/plugin/web_page_cef.h + create mode 100644 src/cef/service/CMakeLists.txt + create mode 100644 src/cef/service/applauncher.proto + create mode 100644 src/cef/service/applauncher_client_grpc.cc + create mode 100644 src/cef/service/applauncher_client_grpc.h + create mode 100644 src/cef/service/wam_ipc.proto + create mode 100644 src/cef/service/web_app_manager_client_grpc.cc + create mode 100644 src/cef/service/web_app_manager_client_grpc.h + create mode 100644 src/cef/service/web_app_manager_service_grpc.cc + create mode 100644 src/cef/service/web_app_manager_service_grpc.h + create mode 100644 src/core/application_installation_handler.h + create mode 100644 src/core/application_installation_handler_stub.cc + create mode 100644 src/core/memory_pressure_level.h + create mode 100644 src/desktop/CMakeLists.txt + create mode 100644 src/desktop/README.md + create mode 100644 src/desktop/web_runtime_desktop.cc + create mode 100644 src/desktop/web_runtime_desktop.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1e9f94f..073e326 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -18,22 +18,24 @@ cmake_minimum_required(VERSION 3.13.0) + + project(WebAppMgr VERSION 1.0.0 LANGUAGES CXX) + +-set(CMAKE_CXX_STANDARD 14) ++set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +-set(CMAKE_BUILD_TYPE Release) + + include(FindPkgConfig) + + set(OS_WEBOS FALSE) + set(OS_AGL FALSE) +-set(PLATFORM_NAME "WebOS" CACHE STRING "Target platform name (WebOS, POKY_AGL)") ++set(OS_DESKTOP FALSE) ++set(WEBENGINE_CEF TRUE) ++set(WEBENGINE_CBE FALSE) ++set(PLATFORM_NAME "Desktop" CACHE STRING "Target platform name (WebOS, POKY_AGL, Desktop)") + string(TOLOWER ${PLATFORM_NAME} PLATFORM) + if(${PLATFORM} STREQUAL "webos") + set(OS_WEBOS TRUE) + elseif(${PLATFORM} MATCHES ".*agl") + set(OS_AGL TRUE) + else() +- message(FATAL_ERROR "Unsupported platform: ${PLATFORM}") ++ set(OS_DESKTOP TRUE) + endif() + + if(OS_WEBOS) +@@ -45,4 +47,12 @@ if(OS_WEBOS) + webos_build_system_bus_files(${CMAKE_SOURCE_DIR}/files/sysbus) + endif() + ++message(STATUS "WAM Configuration:") ++message(STATUS "OS_WEBOS: ${OS_WEBOS}") ++message(STATUS "OS_AGL: ${OS_AGL}") ++message(STATUS "OS_DESKTOP: ${OS_DESKTOP}") ++message(STATUS "WEBENGINE_CEF: ${WEBENGINE_CEF}") ++message(STATUS "WEBENGINE_CBE: ${WEBENGINE_CBE}") ++message(STATUS "PLATFORM_NAME: ${PLATFORM_NAME}") ++ + add_subdirectory(src) +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index 3cca138..173dafc 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -18,10 +18,12 @@ project(WebAppMgrExec VERSION 1.0.0 DESCRIPTION "WAM") + + set(WAM_ROOT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +-if(NOT DEFINED CHROMIUM_SRC_DIR) +- message(FATAL_ERROR "CHROMIUM_SRC_DIR was not set") ++if (WEBVIEW_CBE) ++ if(NOT DEFINED CHROMIUM_SRC_DIR) ++ message(FATAL_ERROR "CHROMIUM_SRC_DIR was not set") ++ endif() ++ set(CHROMIUM_LDFLAGS -lcbe) + endif() +-set(CHROMIUM_LDFLAGS -lcbe) + + find_package(PkgConfig REQUIRED) + find_package(Boost COMPONENTS filesystem REQUIRED) +@@ -39,6 +41,8 @@ elseif(OS_AGL) + find_package(gRPC REQUIRED) + find_program(GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin REQUIRED) + find_package(Threads) ++elseif(OS_DESKTOP) ++ set(DISABLE_PMLOG(true)) + endif() + + if(DISABLE_PMLOG) +@@ -58,7 +62,6 @@ set(WAM_COMPILER_FLAGS -fno-rtti + -Wall + -fpermissive + -funwind-tables +- -std=c++14 + -Wno-psabi + -Werror + ) +@@ -70,29 +73,68 @@ endif() + add_link_options(-Wl,--no-as-needed -Wno-psabi -rdynamic) + + add_subdirectory(core) +-add_subdirectory(platform) + + set(WAM_INCLUDE_DIRS + ${GLIB_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}/core + ${CMAKE_CURRENT_SOURCE_DIR}/util +- ${CMAKE_CURRENT_SOURCE_DIR}/webos + ) + + set(WAM_LIBS + ${CHROMIUM_LDFLAGS} + ${PMLOGLIB_LDFLAGS} +- WebAppMgr + WebAppMgrCore + ) + ++if(WEBENGINE_CBE) ++ add_subdirectory(platform) ++ LIST(APPEND WAM_INCLUDE_DIRS ++ ${CMAKE_CURRENT_SOURCE_DIR}/webos ++ ) ++ LIST(APPEND WAM_LIBS ++ WebAppMgr ++ ) ++endif() ++ ++if(OS_DESKTOP OR WEBENGINE_CEF) ++ if(NOT DEFINED CEF_ROOT) ++ message(FATAL_ERROR "CEF_ROOT needs to point to the binary distribution directory") ++ endif() ++ ++ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CEF_ROOT}/cmake") ++ find_package(CEF REQUIRED) ++ message(STATUS "CEF lib location: ${CEF_LIB_RELEASE}") ++ print_cef_config() ++ ++ add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper) ++ add_library(libcef_lib SHARED IMPORTED) ++ set_target_properties(libcef_lib PROPERTIES IMPORTED_LOCATION ${CEF_LIB_RELEASE}) ++ target_link_libraries(libcef_dll_wrapper libcef_lib) ++ ++ LIST(APPEND WAM_LIBS libcef_lib libcef_dll_wrapper) ++endif() ++ ++if(OS_DESKTOP) ++ add_subdirectory(desktop) ++ add_subdirectory(cef/service) ++ add_subdirectory(cef/cli) ++ LIST(APPEND WAM_LIBS WebAppMgrDesktop) ++endif() ++ + if(OS_WEBOS) + add_subdirectory(plugin) + add_subdirectory(tests) + add_subdirectory(testplugin) + LIST(APPEND WAM_LIBS ${LIBLUNAPREFS_LDFLAGS}) + elseif(OS_AGL) +- add_subdirectory(agl/plugin) ++ if(WEBENGINE_CEF) ++ add_subdirectory(agl-cef) ++ add_subdirectory(cef/service) ++ add_subdirectory(cef/cli) ++ LIST(APPEND WAM_LIBS WebAppMgrAGLCEF) ++ else() ++ add_subdirectory(agl/plugin) ++ endif() + LIST(APPEND WAM_INCLUDE_DIRS + ${Protobuf_INCLUDE_DIRS} + ${gRPC_INCLUDE_DIRS} +diff --git a/src/agl-cef/CMakeLists.txt b/src/agl-cef/CMakeLists.txt +new file mode 100644 +index 0000000..8d29004 +--- /dev/null ++++ b/src/agl-cef/CMakeLists.txt +@@ -0,0 +1,54 @@ ++project(WebAppMgrAGLCEF VERSION 1.0.0 DESCRIPTION "Web Application Manager library") ++ ++set(WAM_LIB_LIBS ++ ${JSONCPP_LDFLAGS} ++ WebAppMgrCore ++ WebAppMgrService ++ libcef_lib ++ libcef_dll_wrapper ++) ++ ++set(SOURCES ++ web_runtime_agl_cef.cc ++) ++ ++set(HEADERS ++ web_runtime_agl_cef.h ++) ++ ++set(WAM_LIB_CEF_DIR ${WAM_ROOT_SOURCE_DIR}/cef) ++ ++set(WAM_LIB_INCLUDE_DIRS ++ ${JSONCPP_INCLUDE_DIRS} ++ ${CEF_INCLUDE_PATH} ++) ++ ++LIST(APPEND SOURCES ++ ${WAM_LIB_CEF_DIR}/device_info_cef.cc ++ ${WAM_LIB_CEF_DIR}/platform_module_factory_cef.cc ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_browser_handler.cc ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_client.cc ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_render_handler.cc ++) ++LIST(APPEND HEADERS ++ ${WAM_LIB_CEF_DIR}/device_info_cef.h ++ ${WAM_LIB_CEF_DIR}/platform_module_factory_cef.h ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_browser_handler.h ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_client.h ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_render_handler.cc ++) ++LIST(APPEND WAM_LIB_INCLUDE_DIRS ++ ${WAM_LIB_CEF_DIR} ++ ${WAM_LIB_CEF_DIR}/handlers ++) ++ ++add_library(${PROJECT_NAME} SHARED ${HEADERS} ${SOURCES}) ++target_include_directories(${PROJECT_NAME} PUBLIC ${WAM_LIB_INCLUDE_DIRS}) ++set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1.0) ++ ++install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/webappmanager) ++ ++target_link_libraries(${PROJECT_NAME} PUBLIC ${WAM_LIB_LIBS}) ++install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++ ++add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/plugin) +diff --git a/src/agl-cef/plugin/CMakeLists.txt b/src/agl-cef/plugin/CMakeLists.txt +new file mode 100644 +index 0000000..052c94e +--- /dev/null ++++ b/src/agl-cef/plugin/CMakeLists.txt +@@ -0,0 +1,59 @@ ++project(webappmgr-default-plugin VERSION 1.0.0 DESCRIPTION "Default WAM plugin") ++ ++set(CEF_PLUGINS_DIR ${WAM_ROOT_SOURCE_DIR}/cef/plugin) ++set(CEF_HANDLERS_DIR ${WAM_ROOT_SOURCE_DIR}/cef/handlers) ++ ++set (SOURCES ++ ${CEF_HANDLERS_DIR}/wam_cef_client.cc ++ ${CEF_PLUGINS_DIR}/web_app_cef.cc ++ ${CEF_PLUGINS_DIR}/web_page_cef.cc ++ agl_cef_context.cc ++ web_app_factory_agl_cef.cc ++ background_cef_app.cc ++ homescreen_cef_app.cc ++ regular_cef_app.cc ++) ++set (HEADERS ++ ${CEF_HANDLERS_DIR}/wam_cef_client.h ++ ${CEF_PLUGINS_DIR}/web_app_cef.h ++ ${CEF_PLUGINS_DIR}/web_page_cef.h ++ agl_cef_context.h ++ web_app_factory_agl_cef.h ++ background_cef_app.h ++ homescreen_cef_app.h ++ regular_cef_app.h ++) ++set (WAM_PLUGIN_INCLUDE_DIRS ++ ${CEF_HANDLERS_DIR} ++ ${CEF_PLUGINS_DIR} ++ ${WAM_ROOT_SOURCE_DIR} ++ ${WAM_ROOT_SOURCE_DIR}/core ++ ${WAM_ROOT_SOURCE_DIR}/platform ++ ${WAM_ROOT_SOURCE_DIR}/platform/webengine ++ ${WAM_ROOT_SOURCE_DIR}/util ++ ${CEF_INCLUDE_PATH} ++) ++set(WAM_PLUGIN_LIBS ++ WebAppMgrService ++ WebAppMgrService-grpc ++ libcef_lib ++ libcef_dll_wrapper ++) ++ ++if (OS_DESKTOP) ++ LIST(APPEND WAM_PLUGIN_LIBS ++ WebAppMgrDesktop ++ ) ++else() ++ LIST(APPEND WAM_PLUGIN_LIBS ++ WebAppMgrAGLCEF ++ ) ++endif() ++ ++add_library(${PROJECT_NAME} SHARED ${HEADERS} ${SOURCES}) ++add_dependencies(${PROJECT_NAME} libcef_lib libcef_dll_wrapper) ++ ++target_include_directories(${PROJECT_NAME} PRIVATE ${WAM_PLUGIN_INCLUDE_DIRS}) ++target_link_libraries(${PROJECT_NAME} PRIVATE ${WAM_PLUGIN_LIBS}) ++install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/webappmanager/plugins) ++install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webappmanager) +diff --git a/src/agl-cef/plugin/agl_cef_context.cc b/src/agl-cef/plugin/agl_cef_context.cc +new file mode 100644 +index 0000000..8c1a390 +--- /dev/null ++++ b/src/agl-cef/plugin/agl_cef_context.cc +@@ -0,0 +1,4 @@ ++#include "agl_cef_context.h" ++ ++AglCefContext* AglCefContext::instance_ = nullptr; ++ +diff --git a/src/agl-cef/plugin/agl_cef_context.h b/src/agl-cef/plugin/agl_cef_context.h +new file mode 100644 +index 0000000..a1e698f +--- /dev/null ++++ b/src/agl-cef/plugin/agl_cef_context.h +@@ -0,0 +1,42 @@ ++#ifndef AGL_CEF_PLUGIN_AGL_CEF_CONTEXT_H ++#define AGL_CEF_PLUGIN_AGL_CEF_CONTEXT_H ++ ++#include <memory> ++ ++class AglCefContext { ++ public: ++ AglCefContext(const AglCefContext&) = delete; ++ AglCefContext& operator=(const AglCefContext&) = delete; ++ ++ static AglCefContext* get() { ++ if (!instance_) { ++ instance_ = new AglCefContext(); ++ } ++ return instance_; ++ } ++ ++ uint32_t activation_area_width() const { return activation_area_width_; } ++ void set_activation_area_width(uint32_t activation_area_width) { ++ activation_area_width_ = activation_area_width; ++ } ++ ++ uint32_t activation_area_height() const { return activation_area_height_; } ++ void set_activation_area_height(uint32_t activation_area_height) { ++ activation_area_height_ = activation_area_height; ++ } ++ ++ uint32_t panel_offset() const { return panel_offset_; } ++ void set_panel_offset(uint32_t panel_offset) { ++ panel_offset_ = panel_offset; ++ } ++ ++ private: ++ AglCefContext() = default; ++ ++ static AglCefContext* instance_; ++ uint32_t activation_area_width_ = 0; ++ uint32_t activation_area_height_ = 0; ++ uint32_t panel_offset_ = 0; ++}; ++ ++#endif // AGL_CEF_PLUGIN_AGL_CEF_CONTEXT_H +diff --git a/src/agl-cef/plugin/background_cef_app.cc b/src/agl-cef/plugin/background_cef_app.cc +new file mode 100644 +index 0000000..c406641 +--- /dev/null ++++ b/src/agl-cef/plugin/background_cef_app.cc +@@ -0,0 +1,33 @@ ++#include "background_cef_app.h" ++ ++BackgroundCefApp::BackgroundCefApp(std::shared_ptr<ApplicationDescription> app_desc) ++ : WebAppCEF(app_desc) { ++ CefRect display_bounds = GetDisplayBounds(); ++ width_override_ = display_bounds.width; ++ height_override_ = display_bounds.height; ++} ++ ++BackgroundCefApp::~BackgroundCefApp() {} ++ ++void BackgroundCefApp::Init(int width, ++ int height, ++ AglShellSurfaceType surface_type, ++ AglShellPanelEdge panel_type) { ++ if (!IsReady()) { ++ return; ++ } ++ ++ /* ++ // TODO: change when in portrait mode ++ window_->SetupActivationArea(AglCefContext::get()->panel_offset(), ++ 0, ++ AglCefContext::get()->activation_area_width(), ++ AglCefContext::get()->activation_area_height()); ++ */ ++ ++ WebAppCEF::Init(width, height, surface_type, panel_type); ++} ++ ++bool BackgroundCefApp::IsReady() const { ++ return window_ != nullptr; ++} +diff --git a/src/agl-cef/plugin/background_cef_app.h b/src/agl-cef/plugin/background_cef_app.h +new file mode 100644 +index 0000000..6681b5d +--- /dev/null ++++ b/src/agl-cef/plugin/background_cef_app.h +@@ -0,0 +1,20 @@ ++#ifndef AGL_CEF_PLUGIN_BACKGROUND_CEF_APP_H ++#define AGL_CEF_PLUGIN_BACKGROUND_CEF_APP_H ++ ++#include "agl_cef_context.h" ++#include "web_app_cef.h" ++ ++class BackgroundCefApp : public WebAppCEF { ++ public: ++ BackgroundCefApp(std::shared_ptr<ApplicationDescription> app_desc); ++ ~BackgroundCefApp(); ++ ++ void Init(int width, ++ int height, ++ AglShellSurfaceType surface_type, ++ AglShellPanelEdge panel_type) override; ++ ++ bool IsReady() const override; ++}; ++ ++#endif // AGL_CEF_PLUGIN_BACKGROUND_CEF_APP_H +diff --git a/src/agl-cef/plugin/homescreen_cef_app.cc b/src/agl-cef/plugin/homescreen_cef_app.cc +new file mode 100644 +index 0000000..cc6af64 +--- /dev/null ++++ b/src/agl-cef/plugin/homescreen_cef_app.cc +@@ -0,0 +1,25 @@ ++#include "homescreen_cef_app.h" ++ ++#include "agl_cef_context.h" ++ ++HomescreenCefApp::HomescreenCefApp(std::shared_ptr<ApplicationDescription> app_desc) ++ : WebAppCEF(app_desc) { ++ CefRect display_bounds = GetDisplayBounds(); ++ uint32_t panel_offset = app_desc->WidthOverride(); // TODO: height when in portrait mode ++ uint32_t activation_width = display_bounds.width - panel_offset - 1; ++ uint32_t activation_height = display_bounds.height; ++ ++ // TODO: change when in portrait mode ++ width_override_ = panel_offset; ++ height_override_ = activation_height; ++ ++ AglCefContext::get()->set_panel_offset(panel_offset); ++ AglCefContext::get()->set_activation_area_width(activation_width); ++ AglCefContext::get()->set_activation_area_height(activation_height); ++} ++ ++HomescreenCefApp::~HomescreenCefApp() {} ++ ++bool HomescreenCefApp::IsReady() const { ++ return window_ && window_->IsSurfaceConfigured(); ++} +diff --git a/src/agl-cef/plugin/homescreen_cef_app.h b/src/agl-cef/plugin/homescreen_cef_app.h +new file mode 100644 +index 0000000..c4f86ab +--- /dev/null ++++ b/src/agl-cef/plugin/homescreen_cef_app.h +@@ -0,0 +1,15 @@ ++#ifndef AGL_CEF_PLUGIN_HOMESCREEN_CEF_APP_H ++#define AGL_CEF_PLUGIN_HOMESCREEN_CEF_APP_H ++ ++#include "web_app_cef.h" ++ ++class HomescreenCefApp : public WebAppCEF { ++ public: ++ HomescreenCefApp(std::shared_ptr<ApplicationDescription> app_desc); ++ ~HomescreenCefApp(); ++ ++ protected: ++ bool IsReady() const override; ++}; ++ ++#endif // AGL_CEF_PLUGIN_BACKGROUND_CEF_APP_H +diff --git a/src/agl-cef/plugin/regular_cef_app.cc b/src/agl-cef/plugin/regular_cef_app.cc +new file mode 100644 +index 0000000..a882314 +--- /dev/null ++++ b/src/agl-cef/plugin/regular_cef_app.cc +@@ -0,0 +1,11 @@ ++#include "regular_cef_app.h" ++ ++#include "agl_cef_context.h" ++ ++RegularCefApp::RegularCefApp(std::shared_ptr<ApplicationDescription> app_desc) ++ : WebAppCEF(app_desc) { ++ width_override_ = AglCefContext::get()->activation_area_width(); ++ height_override_ = AglCefContext::get()->activation_area_height(); ++} ++ ++RegularCefApp::~RegularCefApp() {} +diff --git a/src/agl-cef/plugin/regular_cef_app.h b/src/agl-cef/plugin/regular_cef_app.h +new file mode 100644 +index 0000000..ed4b34d +--- /dev/null ++++ b/src/agl-cef/plugin/regular_cef_app.h +@@ -0,0 +1,12 @@ ++#ifndef AGL_CEF_PLUGIN_REGULAR_CEF_APP_H ++#define AGL_CEF_PLUGIN_REGULAR_CEF_APP_H ++ ++#include "web_app_cef.h" ++ ++class RegularCefApp : public WebAppCEF { ++ public: ++ RegularCefApp(std::shared_ptr<ApplicationDescription> app_desc); ++ ~RegularCefApp(); ++}; ++ ++#endif // AGL_CEF_PLUGIN_REGULAR_CEF_APP_H +diff --git a/src/agl-cef/plugin/web_app_factory_agl_cef.cc b/src/agl-cef/plugin/web_app_factory_agl_cef.cc +new file mode 100644 +index 0000000..8ca2ba8 +--- /dev/null ++++ b/src/agl-cef/plugin/web_app_factory_agl_cef.cc +@@ -0,0 +1,49 @@ ++#include "web_app_factory_agl_cef.h" ++ ++#include "application_description.h" ++#include "plugin_interface.h" ++ ++#include "background_cef_app.h" ++#include "homescreen_cef_app.h" ++#include "regular_cef_app.h" ++ ++#include "web_page_cef.h" ++ ++#include "wam_cef_client.h" ++ ++const char* kPluginApplicationType = "default"; ++ ++WebAppFactoryInterface* CreateInstance() { ++ return new WebAppFactoryCEF(); ++} ++ ++void DeleteInstance(WebAppFactoryInterface* interface) { ++ delete interface; ++} ++ ++WebAppBase* WebAppFactoryCEF::CreateWebApp( ++ const std::string&, ++ std::shared_ptr<ApplicationDescription> app_desc) { ++ std::string app_id = app_desc->Id(); ++ ++ if (app_id == "homescreen") { ++ return new HomescreenCefApp(app_desc); ++ } else if (app_id == "webapps-html5-background") { ++ return new BackgroundCefApp(app_desc); ++ } ++ return new RegularCefApp(app_desc); ++} ++ ++WebAppBase* WebAppFactoryCEF::CreateWebApp( ++ const std::string& win_type, ++ WebPageBase*, ++ std::shared_ptr<ApplicationDescription> desc) { ++ return CreateWebApp(win_type, desc); ++} ++ ++WebPageBase* WebAppFactoryCEF::CreateWebPage( ++ const wam::Url& url, ++ std::shared_ptr<ApplicationDescription> app_desc, ++ const std::string&) { ++ return new WebPageCEF(app_desc, url.ToString()); ++} +diff --git a/src/agl-cef/plugin/web_app_factory_agl_cef.h b/src/agl-cef/plugin/web_app_factory_agl_cef.h +new file mode 100644 +index 0000000..eb4b7ba +--- /dev/null ++++ b/src/agl-cef/plugin/web_app_factory_agl_cef.h +@@ -0,0 +1,23 @@ ++#ifndef AGL_CEF_PLUGIN_WEB_APP_FACTORY_CEF_H ++#define AGL_CEF_PLUGIN_WEB_APP_FACTORY_CEF_H ++ ++#include <memory> ++#include <string> ++ ++#include "web_app_factory_interface.h" ++ ++class WebAppFactoryCEF : public WebAppFactoryInterface { ++ public: ++ WebAppBase* CreateWebApp( ++ const std::string& win_type, ++ std::shared_ptr<ApplicationDescription> desc = 0) override; ++ WebAppBase* CreateWebApp( ++ const std::string& win_type, ++ WebPageBase* page, ++ std::shared_ptr<ApplicationDescription> desc = 0) override; ++ WebPageBase* CreateWebPage(const wam::Url& url, ++ std::shared_ptr<ApplicationDescription> desc, ++ const std::string& launchParams = "") override; ++}; ++ ++#endif // AGL_CEF_PLUGIN_WEB_APP_FACTORY_CEF_H +diff --git a/src/agl-cef/web_runtime_agl_cef.cc b/src/agl-cef/web_runtime_agl_cef.cc +new file mode 100644 +index 0000000..9bc1bd6 +--- /dev/null ++++ b/src/agl-cef/web_runtime_agl_cef.cc +@@ -0,0 +1,63 @@ ++#include "web_runtime_agl_cef.h" ++ ++#include "include/cef_base.h" ++#include "include/cef_origin_whitelist.h" ++ ++#include "wam_cef_browser_handler.h" ++#include "wam_cef_render_handler.h" ++ ++const char kProcessType[] = "type"; ++const char kRendererProcess[] = "renderer"; ++const char kZygoteProcess[] = "zygote"; ++ ++class WamCefUtilityHandler : public CefApp { ++ public: ++ WamCefUtilityHandler () {} ++ ++ private: ++ IMPLEMENT_REFCOUNTING(WamCefUtilityHandler); ++ DISALLOW_COPY_AND_ASSIGN(WamCefUtilityHandler); ++}; ++ ++int WebRuntimeCEF::Run(int argc, char** argv) { ++ CefMainArgs main_args(argc, argv); ++ ++ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine(); ++ command_line->InitFromArgv(main_args.argc, main_args.argv); ++ ++ std::string app_id = command_line->GetSwitchValue("appid"); ++ if (app_id.empty()) { ++ app_id = "WebAppMgr"; ++ } ++ ++ CefRefPtr<CefApp> app; ++ if (!command_line->HasSwitch(kProcessType)) { ++ app = new WamCefBrowserHandler(); ++ } else { ++ const std::string& process_type = command_line->GetSwitchValue(kProcessType); ++ if (process_type == kRendererProcess || process_type == kZygoteProcess) { ++ app = new WamCefRenderHandler(); ++ } else { ++ app = new WamCefUtilityHandler(); ++ } ++ } ++ ++ auto exit_code = CefExecuteProcess(main_args, app.get(), nullptr); ++ if (exit_code >= 0) { ++ return exit_code; ++ } ++ ++ CefSettings settings; ++ settings.remote_debugging_port = 9998; ++ CefInitialize(main_args, settings, app.get(), nullptr); ++ ++ CefRunMessageLoop(); ++ ++ CefShutdown(); ++ ++ return 0; ++} ++ ++std::unique_ptr<WebRuntime> WebRuntime::Create() { ++ return std::make_unique<WebRuntimeCEF>(); ++} +diff --git a/src/agl-cef/web_runtime_agl_cef.h b/src/agl-cef/web_runtime_agl_cef.h +new file mode 100644 +index 0000000..049e554 +--- /dev/null ++++ b/src/agl-cef/web_runtime_agl_cef.h +@@ -0,0 +1,11 @@ ++#ifndef AGL_CEF_WEB_RUNTIME_AGL_CEF_H_ ++#define AGL_CEF_WEB_RUNTIME_AGL_CEF_H_ ++ ++#include "web_runtime.h" ++ ++class WebRuntimeCEF : public WebRuntime { ++ public: ++ int Run(int argc, char** argv) override; ++}; ++ ++#endif // AGL_CEF_WEB_RUNTIME_CEF_H_ +diff --git a/src/agl/web_runtime_agl.cc b/src/agl/web_runtime_agl.cc +index ce8525b..c791c70 100644 +--- a/src/agl/web_runtime_agl.cc ++++ b/src/agl/web_runtime_agl.cc +@@ -128,7 +128,7 @@ void SingleBrowserProcessWebAppLauncher::Launch( + } + + int SingleBrowserProcessWebAppLauncher::Loop(int argc, +- const char** argv, ++ char** argv, + volatile sig_atomic_t& e_flag) { + AGLMainDelegateWAM delegate; + webos::WebOSMain webOSMain(&delegate); +@@ -154,7 +154,7 @@ void SharedBrowserProcessWebAppLauncher::Launch( + } + + int SharedBrowserProcessWebAppLauncher::Loop(int argc, +- const char** argv, ++ char** argv, + volatile sig_atomic_t& e_flag) { + // TODO: wait for a pid + while (e_flag) +@@ -173,7 +173,7 @@ static void AglShellActivateApp(const std::string& app_id) { + WebAppManagerServiceAGL::Instance()->SendEvent(kActivateEvent, app_id); + } + +-int WebAppLauncherRuntime::Run(int argc, const char** argv) { ++int WebAppLauncherRuntime::Run(int argc, char** argv) { + bool is_wait_host_service = IsWaitForHostService(); + std::string app_id = IsActivateApp(Args::Instance()); + +@@ -334,7 +334,7 @@ bool WebAppLauncherRuntime::ParseJsonConfig(const char* path_to_config) { + return true; + } + +-int SharedBrowserProcessRuntime::Run(int argc, const char** argv) { ++int SharedBrowserProcessRuntime::Run(int argc, char** argv) { + if (WebAppManagerServiceAGL::Instance()->InitializeAsHostService()) { + AGLMainDelegateWAM delegate; + webos::WebOSMain webOSMain(&delegate); +@@ -347,7 +347,7 @@ int SharedBrowserProcessRuntime::Run(int argc, const char** argv) { + } + } + +-int RenderProcessRuntime::Run(int argc, const char** argv) { ++int RenderProcessRuntime::Run(int argc, char** argv) { + AGLMainDelegateWAM delegate; + webos::WebOSMain webOSMain(&delegate); + return webOSMain.Run(argc, argv); +@@ -372,7 +372,7 @@ static void print_help(void) { + exit(EXIT_FAILURE); + } + +-void Args::parse_args(int argc, const char** argv) { ++void Args::parse_args(int argc, char** argv) { + int c; + int option_index; + opterr = 0; +@@ -427,7 +427,7 @@ void Args::parse_args(int argc, const char** argv) { + } + } + +-void Args::copy_cmdline(int argc, const char** argv) { ++void Args::copy_cmdline(int argc, char** argv) { + new_argc = argc; + new_argv = static_cast<char**>(calloc(new_argc + 1, sizeof(*new_argv))); + +@@ -446,7 +446,7 @@ void Args::clear_cmdline(void) { + free(new_argv); + } + +-int WebRuntimeAGL::Run(int argc, const char** argv) { ++int WebRuntimeAGL::Run(int argc, char** argv) { + int ret; + Args::Instance()->parse_args(argc, argv); + +diff --git a/src/agl/web_runtime_agl.h b/src/agl/web_runtime_agl.h +index ad045c2..14bc0ed 100644 +--- a/src/agl/web_runtime_agl.h ++++ b/src/agl/web_runtime_agl.h +@@ -39,7 +39,7 @@ class Args { + static Args* args = new Args(); + return args; + } +- void parse_args(int argc, const char** argv); ++ void parse_args(int argc, char** argv); + + inline void set_flag(unsigned int flag) { flags |= flag; } + +@@ -56,7 +56,7 @@ class Args { + + private: + uint32_t flags = FLAG_NONE; +- void copy_cmdline(int argc, const char** argv); ++ void copy_cmdline(int argc, char** argv); + char** new_argv; + int new_argc; + }; +@@ -69,9 +69,7 @@ class Launcher { + AglShellPanelEdge panel_edge, + int width, + int height) = 0; +- virtual int Loop(int argc, +- const char** argv, +- volatile sig_atomic_t& e_flag) = 0; ++ virtual int Loop(int argc, char** argv, volatile sig_atomic_t& e_flag) = 0; + }; + + class SharedBrowserProcessWebAppLauncher : public Launcher { +@@ -82,7 +80,7 @@ class SharedBrowserProcessWebAppLauncher : public Launcher { + AglShellPanelEdge panel_edge, + int width, + int height) override; +- int Loop(int argc, const char** argv, volatile sig_atomic_t& e_flag) override; ++ int Loop(int argc, char** argv, volatile sig_atomic_t& e_flag) override; + }; + + class SingleBrowserProcessWebAppLauncher : public Launcher { +@@ -93,12 +91,12 @@ class SingleBrowserProcessWebAppLauncher : public Launcher { + AglShellPanelEdge panel_edge, + int width, + int height) override; +- int Loop(int argc, const char** argv, volatile sig_atomic_t& e_flag) override; ++ int Loop(int argc, char** argv, volatile sig_atomic_t& e_flag) override; + }; + + class WebAppLauncherRuntime : public WebRuntime { + public: +- int Run(int argc, const char** argv) override; ++ int Run(int argc, char** argv) override; + + private: + bool Init(Args* args); +@@ -127,17 +125,17 @@ class WebAppLauncherRuntime : public WebRuntime { + + class SharedBrowserProcessRuntime : public WebRuntime { + public: +- int Run(int argc, const char** argv) override; ++ int Run(int argc, char** argv) override; + }; + + class RenderProcessRuntime : public WebRuntime { + public: +- int Run(int argc, const char** argv) override; ++ int Run(int argc, char** argv) override; + }; + + class WebRuntimeAGL : public WebRuntime { + public: +- int Run(int argc, const char** argv) override; ++ int Run(int argc, char** argv) override; + + private: + WebRuntime* runtime_; +diff --git a/src/cef/cli/CMakeLists.txt b/src/cef/cli/CMakeLists.txt +new file mode 100644 +index 0000000..1b5f04a +--- /dev/null ++++ b/src/cef/cli/CMakeLists.txt +@@ -0,0 +1,17 @@ ++project(WebAppMgrCli VERSION 1.0.0 DESCRIPTION "Web Application Manager cli helper") ++ ++set(CLI_EXE ${PROJECT_NAME}) ++set(CLI_EXE_INCLUDE_DIRS ++ ${WAM_ROOT_SOURCE_DIR}/util ++) ++ ++set(CLI_EXE_LIBS ++ WebAppMgrCore ++ WebAppMgrService ++ WebAppMgrService-grpc ++) ++ ++add_executable(${CLI_EXE} wam_cli.cc) ++target_include_directories(${CLI_EXE} PUBLIC ${CLI_EXE_INCLUDE_DIRS}) ++target_link_libraries(${CLI_EXE} PUBLIC ${CLI_EXE_LIBS}) ++install(TARGETS ${CLI_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) +diff --git a/src/cef/cli/wam_cli.cc b/src/cef/cli/wam_cli.cc +new file mode 100644 +index 0000000..4775ce4 +--- /dev/null ++++ b/src/cef/cli/wam_cli.cc +@@ -0,0 +1,171 @@ ++// Copyright (c) 2018-2022 LG Electronics, Inc. ++// ++// 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. ++// ++// SPDX-License-Identifier: Apache-2.0 ++ ++#include <getopt.h> ++#include <optional> ++ ++#include "web_app_manager_client_grpc.h" ++ ++#include "log_manager.h" ++ ++class Args { ++ public: ++ enum flags { ++ FLAG_NONE = 0, ++ FLAG_APP_TYPE = 1 << 0, ++ FLAG_ACTIVATE_APP = 1 << 1, ++ FLAG_HTTP_LINK = 1 << 2, ++ FLAG_APP_ID = 1 << 3, ++ FLAG_APP_DIR = 1 << 4, ++ }; ++ ++ static Args* Instance() { ++ static Args* args = new Args(); ++ return args; ++ } ++ void PrintHelp(void) { ++ fprintf(stderr, "WAM: Web Application Manager\n"); ++ fprintf(stderr, ++ "\t[--activate_app=appid] -- activate application. Interrnal " ++ "usage.\n\tNot needing for starting applications.\n"); ++ fprintf(stderr, ++ "\t[--appid=appid] name of an application id.\n\tRequired if " ++ "starting a " ++ "web application.\n"); ++ fprintf( ++ stderr, ++ "\t[--app-install-dir=/path/to/root_index] installation path for web " ++ "application.\n\tRequired if starting a web application.\n"); ++ fprintf(stderr, "\t-h -- this help message \n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ void ParseArgs(int argc, char** argv) { ++ int c; ++ int option_index; ++ opterr = 0; ++ ++ CopyCmdLine(argc, argv); ++ ++ struct option long_opts[] = {{"help", no_argument, 0, 'h'}, ++ {"activate-app", required_argument, 0, 'x'}, ++ {"appid", required_argument, 0, 'a'}, ++ {"app-install-dir", required_argument, 0, 'd'}, ++ {0, 0, 0, 0}}; ++ ++ while ((c = getopt_long(new_argc, new_argv, "ht:a:i:d:", long_opts, ++ &option_index)) != -1) { ++ switch (c) { ++ case 'h': ++ PrintHelp(); ++ break; ++ case 'x': ++ activate_app_id_ = optarg; ++ break; ++ case 'a': ++ app_id_ = optarg; ++ break; ++ case 'd': ++ app_dir_ = optarg; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (optind < new_argc) { ++ // check for 'http://' ++ int p = optind; ++ while (p < new_argc) { ++ if (!strcmp(new_argv[p], "http://")) { ++ http_link_ = new_argv[p]; ++ break; ++ } ++ p++; ++ } ++ } ++ } ++ ++ void ClearCmdLine() { ++ for (int i = 0; i < new_argc; i++) ++ free(new_argv[i]); ++ free(new_argv); ++ } ++ ++ std::string GetAppId() const { ++ return app_id_.has_value() ? *app_id_ : std::string(); ++ } ++ ++ std::string GetAppUri() const { ++ if (http_link_.has_value()) ++ return *http_link_; ++ else if (app_dir_.has_value()) ++ return *app_dir_; ++ return std::string(); ++ } ++ ++ bool HasActivateAppId() const { return activate_app_id_.has_value(); } ++ std::string GetActivateAppId() const { ++ return activate_app_id_.has_value() ? *activate_app_id_ : std::string(); ++ } ++ ++ private: ++ void CopyCmdLine(int argc, char** argv) { ++ new_argc = argc; ++ new_argv = static_cast<char**>(calloc(new_argc + 1, sizeof(*new_argv))); ++ ++ for (int i = 0; i < new_argc; i++) { ++ size_t len = strlen(argv[i]) + 1; ++ new_argv[i] = static_cast<char*>(calloc(len, sizeof(char))); ++ memcpy(new_argv[i], argv[i], len); ++ } ++ ++ new_argv[argc] = nullptr; ++ } ++ char** new_argv; ++ int new_argc; ++ ++ std::optional<std::string> activate_app_id_; ++ std::optional<std::string> http_link_; ++ std::optional<std::string> app_id_; ++ std::optional<std::string> app_dir_; ++}; ++ ++WebAppManagerClientGRPC* GetGrpcClient() { ++ static std::unique_ptr<WebAppManagerClientGRPC> grpc_client; ++ if (!grpc_client) { ++ grpc_client = std::make_unique<WebAppManagerClientGRPC>(); ++ } ++ return grpc_client.get(); ++} ++ ++int main(int argc, char** argv) { ++ auto* args = Args::Instance(); ++ args->ParseArgs(argc, argv); ++ ++ // TODO: handle completed grpc calls ++ // and get the correct ok() result ++ if (args->HasActivateAppId()) { ++ GetGrpcClient()->Activate(args->GetActivateAppId()); ++ } else { ++ WebAppManagerClientGRPC::LaunchParams params; ++ params.app_id = args->GetAppId(); ++ params.uri = args->GetAppUri(); ++ GetGrpcClient()->Launch(params); ++ } ++ ++ return 0; ++} +diff --git a/src/cef/device_info_cef.cc b/src/cef/device_info_cef.cc +new file mode 100644 +index 0000000..f5fd681 +--- /dev/null ++++ b/src/cef/device_info_cef.cc +@@ -0,0 +1,104 @@ ++#include "device_info_cef.h" ++ ++#include <string> ++ ++#include <glib.h> ++#include <json/value.h> ++ ++#include "log_manager.h" ++#include "utils.h" ++ ++DeviceInfoCEF::DeviceInfoCEF() = default; ++ ++void DeviceInfoCEF::Initialize() { ++ const std::string& json_string = ++ util::ReadFile("/var/luna/preferences/localeInfo"); ++ if (json_string.empty()) { ++ return; ++ } ++ ++ Json::Value locale_json = util::StringToJson(json_string); ++ if (!locale_json.isObject() || locale_json.empty() || ++ !locale_json["localeInfo"].isObject() || ++ !locale_json["localeInfo"]["locales"].isObject() || ++ !locale_json["localeInfo"]["locales"]["UI"].isString() || ++ !locale_json["country"].isString() || ++ !locale_json["smartServiceCountryCode3"].isString()) { ++ LOG_ERROR(MSGID_LOCALEINFO_READ_FAIL, 1, ++ PMLOGKS("CONTENT", json_string.c_str()), ""); ++ return; ++ } ++ ++ Json::Value locale_info = locale_json["localeInfo"]; ++ ++ std::string language(locale_info["locales"]["UI"].asString()); ++ std::string localcountry(locale_json["country"].asString()); ++ std::string smartservicecountry( ++ locale_json["smartServiceCountryCode3"].asString()); ++ ++ SetSystemLanguage(language.c_str()); ++ SetDeviceInfo("LocalCountry", localcountry.c_str()); ++ SetDeviceInfo("SmartServiceCountry", smartservicecountry.c_str()); ++} ++ ++void DeviceInfoCEF::InitDisplayInfo() { ++ // Display information ++ // -------------------------------------------------------- ++ float screen_density_ = 1.0f; ++ int hardware_screen_width = 0; ++ int hardware_screen_height = 0; ++ ++ std::string hardware_screen_width_str; ++ std::string hardware_screen_height_str; ++ if (GetDeviceInfo("HardwareScreenWidth", hardware_screen_width_str) && ++ GetDeviceInfo("HardwareScreenHeight", hardware_screen_height_str)) { ++ hardware_screen_width = ++ util::StrToIntWithDefault(hardware_screen_width_str, 0); ++ hardware_screen_height = ++ util::StrToIntWithDefault(hardware_screen_height_str, 0); ++ } else { ++ GetDisplayWidth(hardware_screen_width); ++ GetDisplayHeight(hardware_screen_height); ++ } ++ ++ screen_width_ = static_cast<int>(hardware_screen_width / screen_density_); ++ screen_height_ = static_cast<int>(hardware_screen_height / screen_density_); ++} ++ ++void DeviceInfoCEF::InitPlatformInfo() { ++ // normally like this info ++ /* ++ "modelName": "WEBOS1", ++ "platformVersion": "00.00.00", ++ "platformVersionDot": 00, ++ "platformVersionMajor_pos": 00, ++ "platformVersionMinor": 00, ++ */ ++ ++ std::string value; ++ if (GetDeviceInfo("ModelName", value)) ++ model_name_ = value; ++ if (GetDeviceInfo("FirmwareVersion", value)) ++ platform_version_ = value; ++ ++ size_t major_pos = 0, minor_pos = 0; ++ major_pos = platform_version_.find_first_of('.'); ++ if (major_pos != std::string::npos && ++ major_pos <= platform_version_.size() - 1) ++ minor_pos = platform_version_.find_first_of('.', major_pos + 1); ++ if (major_pos == std::string::npos || minor_pos == std::string::npos) { ++ version_major_ = version_minor_ = version_dot_ = -1; ++ } else { ++ version_major_ = ++ util::StrToIntWithDefault(platform_version_.substr(0, major_pos), 0); ++ version_minor_ = util::StrToIntWithDefault( ++ platform_version_.substr(major_pos + 1, minor_pos), 0); ++ version_dot_ = ++ util::StrToIntWithDefault(platform_version_.substr(minor_pos + 1), 0); ++ } ++} ++ ++void DeviceInfoCEF::GatherInfo() { ++ InitDisplayInfo(); ++ InitPlatformInfo(); ++} +diff --git a/src/cef/device_info_cef.h b/src/cef/device_info_cef.h +new file mode 100644 +index 0000000..e2b3712 +--- /dev/null ++++ b/src/cef/device_info_cef.h +@@ -0,0 +1,38 @@ ++#ifndef CEF_DEVICE_INFO_CEF_H_ ++#define CEF_DEVICE_INFO_CEF_H_ ++ ++#include <string> ++ ++#include "device_info.h" ++ ++class DeviceInfoCEF : public DeviceInfo { ++ public: ++ DeviceInfoCEF(); ++ ++ void Initialize() override; ++ ++ private: ++ int screen_width_ = 0; ++ int screen_height_ = 0; ++ ++ float screen_density_ = 1.0f; ++ ++ std::string model_name_ = "webOS.Open.CEF"; ++ std::string platform_version_ = "00.00.00"; ++ ++ // platform versions are <major>.<minor>.<dot> ++ int version_major_ = 0; ++ int version_minor_ = 0; ++ int version_dot_ = 0; ++ ++ bool support_3d_ = false; ++ std::string ota_id_; ++ std::string hardware_version_ = "0x00000001"; ++ std::string firmware_version_ = "00.00.01"; ++ ++ void InitDisplayInfo(); ++ void InitPlatformInfo(); ++ void GatherInfo(); ++}; ++ ++#endif // CEF_DEVICE_INFO_IMPL_H_ +diff --git a/src/cef/handlers/wam_cef_browser_handler.cc b/src/cef/handlers/wam_cef_browser_handler.cc +new file mode 100644 +index 0000000..0708363 +--- /dev/null ++++ b/src/cef/handlers/wam_cef_browser_handler.cc +@@ -0,0 +1,31 @@ ++#include "wam_cef_browser_handler.h" ++ ++#include "log_manager.h" ++#include "log_msg_id.h" ++#include "platform_module_factory_cef.h" ++#include "wam_cef_client.h" ++#include "web_app_manager_service_grpc.h" ++ ++WamCefBrowserHandler::WamCefBrowserHandler() : ++ client_(new WamCefClient()) { ++ WebAppManager::Instance()->SetPlatformModules( ++ std::make_unique<PlatformModuleFactoryCEF>()); ++} ++ ++WamCefBrowserHandler::~WamCefBrowserHandler() {} ++ ++CefRefPtr<CefBrowserProcessHandler> WamCefBrowserHandler::GetBrowserProcessHandler() { ++ return this; ++} ++ ++CefRefPtr<CefClient> WamCefBrowserHandler::GetDefaultClient() { ++ return client_; ++} ++ ++void WamCefBrowserHandler::OnContextInitialized() { ++ if (!WebAppManagerServiceGRPC::Instance()->InitializeAsHostService()) { ++ LOG_ERROR(MSGID_ERROR_CANNOT_LOCK_SERVICE, 0, ++ "Cannot lock WAM GRPC service IPC"); ++ } ++ WebAppManagerServiceGRPC::Instance()->StartService(); ++} +diff --git a/src/cef/handlers/wam_cef_browser_handler.h b/src/cef/handlers/wam_cef_browser_handler.h +new file mode 100644 +index 0000000..58c7f20 +--- /dev/null ++++ b/src/cef/handlers/wam_cef_browser_handler.h +@@ -0,0 +1,23 @@ ++#ifndef CEF_HANDLERS_WAM_CEF_BROWSER_HANDLER_H ++#define CEF_HANDLERS_WAM_CEF_BROWSER_HANDLER_H ++ ++#include "include/cef_app.h" ++#include "include/cef_browser_process_handler.h" ++ ++#include "wam_cef_client.h" ++ ++class WamCefBrowserHandler : public CefApp, public CefBrowserProcessHandler { ++ public: ++ WamCefBrowserHandler(); ++ virtual ~WamCefBrowserHandler(); ++ ++ CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override; ++ CefRefPtr<CefClient> GetDefaultClient() override; ++ void OnContextInitialized() override; ++ ++ private: ++ IMPLEMENT_REFCOUNTING(WamCefBrowserHandler); ++ CefRefPtr<WamCefClient> client_; ++}; ++ ++#endif // CEF_HANDLERS_WAM_CEF_BROWSER_HANDLER_H +diff --git a/src/cef/handlers/wam_cef_client.cc b/src/cef/handlers/wam_cef_client.cc +new file mode 100644 +index 0000000..5ba6201 +--- /dev/null ++++ b/src/cef/handlers/wam_cef_client.cc +@@ -0,0 +1,39 @@ ++#include "wam_cef_client.h" ++ ++#include "include/wrapper/cef_helpers.h" ++ ++WamCefClient* g_instance = nullptr; ++ ++WamCefClient::WamCefClient() { ++ DCHECK(!g_instance); ++ g_instance = this; ++} ++ ++// static ++WamCefClient* WamCefClient::GetInstance() { ++ return g_instance; ++} ++ ++bool WamCefClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefProcessId source_process, ++ CefRefPtr<CefProcessMessage> message) { ++ std::string message_name = message->GetName(); ++ CefRefPtr<CefListValue> args = message->GetArgumentList(); ++ if (message_name == "start") { ++ if (args->GetSize() != 1) { ++ return false; ++ } ++ std::string app_id = args->GetString(0); ++ applauncher_.Start(app_id); ++ return true; ++ } else if (message_name == "get_applications") { ++ if (args->GetSize() != 1) { ++ return false; ++ } ++ bool only_graphical = args->GetBool(0); ++ applauncher_.GetApplications(browser, only_graphical); ++ return true; ++ } ++ return false; ++} +diff --git a/src/cef/handlers/wam_cef_client.h b/src/cef/handlers/wam_cef_client.h +new file mode 100644 +index 0000000..3189c42 +--- /dev/null ++++ b/src/cef/handlers/wam_cef_client.h +@@ -0,0 +1,31 @@ ++#ifndef CEF_HANDLERS_WAM_CEF_CLIENT_H ++#define CEF_HANDLERS_WAM_CEF_CLIENT_H ++ ++#include "include/cef_client.h" ++ ++#include "applauncher_client_grpc.h" ++ ++class WamCefClient : public CefClient, ++ public CefLifeSpanHandler { ++ public: ++ WamCefClient(); ++ ++ static WamCefClient* GetInstance(); ++ ++ CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { ++ return this; ++ } ++ ++ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefProcessId source_process, ++ CefRefPtr<CefProcessMessage> message) override; ++ ++ private: ++ AppLauncherClientGRPC applauncher_; ++ ++ IMPLEMENT_REFCOUNTING(WamCefClient); ++ DISALLOW_COPY_AND_ASSIGN(WamCefClient); ++}; ++ ++#endif // CEF_HANDLERS_WAM_CEF_CLIENT_H +diff --git a/src/cef/handlers/wam_cef_render_handler.cc b/src/cef/handlers/wam_cef_render_handler.cc +new file mode 100644 +index 0000000..48c881a +--- /dev/null ++++ b/src/cef/handlers/wam_cef_render_handler.cc +@@ -0,0 +1,135 @@ ++#include "wam_cef_render_handler.h" ++ ++#include "include/cef_parser.h" ++#include "include/cef_process_message.h" ++ ++WamCefRenderHandler::WamCefRenderHandler() {} ++ ++void WamCefRenderHandler::OnContextCreated(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefRefPtr<CefV8Context> context) { ++ ++ CefRefPtr<CefV8Value> app_service = CefV8Value::CreateObject(nullptr, nullptr); ++ ++ CefRefPtr<CefV8Value> start = CefV8Value::CreateFunction("start", this); ++ app_service->SetValue("start", start, V8_PROPERTY_ATTRIBUTE_NONE); ++ ++ CefRefPtr<CefV8Value> get_applications = CefV8Value::CreateFunction("getApplications", this); ++ app_service->SetValue("getApplications", get_applications, V8_PROPERTY_ATTRIBUTE_NONE); ++ ++ CefRefPtr<CefV8Value> global = context->GetGlobal(); // window object ++ CefRefPtr<CefV8Value> navigator = global->GetValue("navigator"); ++ ++ navigator->SetValue("appService", app_service, V8_PROPERTY_ATTRIBUTE_NONE); ++} ++ ++void WamCefRenderHandler::OnContextReleased(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefRefPtr<CefV8Context> context) { ++ if (callback_map_.empty()) { ++ return; ++ } ++ ++ CallbackMap::iterator it = callback_map_.begin(); ++ for (; it != callback_map_.end();) { ++ if (it->second.first->IsSame(context)) { ++ callback_map_.erase(it++); ++ } else { ++ ++it; ++ } ++ } ++} ++ ++void WamCefRenderHandler::Start(const std::string &app_id) { ++ CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create("start"); ++ CefRefPtr<CefListValue> args = message->GetArgumentList(); ++ args->SetString(0, app_id); ++ auto context = CefV8Context::GetCurrentContext(); ++ context->GetFrame()->SendProcessMessage(PID_BROWSER, message); ++} ++ ++void WamCefRenderHandler::GetApplications(bool only_graphical, CefRefPtr<CefV8Value> callback) { ++ std::string message_name = "get_applications"; ++ ++ // store the callback until we receive the browser's response ++ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); ++ int browser_id = context->GetBrowser()->GetIdentifier(); ++ callback_map_.insert( ++ std::make_pair(std::make_pair(message_name, browser_id), ++ std::make_pair(context, callback))); ++ ++ CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(message_name); ++ CefRefPtr<CefListValue> args = message->GetArgumentList(); ++ args->SetBool(0, only_graphical); ++ context->GetFrame()->SendProcessMessage(PID_BROWSER, message); ++} ++ ++bool WamCefRenderHandler::Execute(const CefString& name, ++ CefRefPtr<CefV8Value> object, ++ const CefV8ValueList& arguments, ++ CefRefPtr<CefV8Value>& retval, ++ CefString& exception) { ++ if (name == "start") { ++ if (arguments.size() != 1 || !arguments[0]->IsString()) { ++ return false; ++ } ++ std::string app_id = arguments[0]->GetStringValue(); ++ Start(app_id); ++ return true; ++ } else if (name == "getApplications") { ++ if (arguments.size() != 2 || ++ !arguments[0]->IsBool() || ++ !arguments[1]->IsFunction()) { ++ return false; ++ } ++ GetApplications(arguments[0]->GetBoolValue(), arguments[1]); ++ return true; ++ } ++ ++ return false; ++} ++ ++bool WamCefRenderHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefProcessId source_process, ++ CefRefPtr<CefProcessMessage> message) { ++ std::string message_name = message->GetName(); ++ CefRefPtr<CefListValue> args = message->GetArgumentList(); ++ if (message_name == "get_applications") { ++ CallbackMap::const_iterator it = callback_map_.find( ++ std::make_pair(message_name, ++ browser->GetIdentifier())); ++ if (it == callback_map_.end()) { ++ return false; ++ } ++ ++ CefRefPtr<CefV8Context> context = it->second.first; ++ CefRefPtr<CefV8Value> callback = it->second.second; ++ ++ context->Enter(); ++ ++ CefRefPtr<CefValue> apps_list_value = CefParseJSON(args->GetString(0), JSON_PARSER_RFC); ++ ++ CefRefPtr<CefListValue> list = apps_list_value->GetList(); ++ int size = list->GetSize(); ++ CefRefPtr<CefV8Value> apps_list = CefV8Value::CreateArray(size); ++ for (int i = 0; i < size; i++) { ++ CefRefPtr<CefDictionaryValue> app_info_dict = list->GetDictionary(i); ++ CefRefPtr<CefV8Value> dict = CefV8Value::CreateObject(nullptr, nullptr); ++ dict->SetValue("id", CefV8Value::CreateString(app_info_dict->GetString("id")), V8_PROPERTY_ATTRIBUTE_NONE); ++ dict->SetValue("name", CefV8Value::CreateString(app_info_dict->GetString("name")), V8_PROPERTY_ATTRIBUTE_NONE); ++ dict->SetValue("icon", CefV8Value::CreateString(app_info_dict->GetString("icon")), V8_PROPERTY_ATTRIBUTE_NONE); ++ apps_list->SetValue(i, dict); ++ } ++ ++ CefV8ValueList arguments; ++ arguments.push_back(apps_list); ++ callback->ExecuteFunctionWithContext(context, nullptr, arguments); ++ ++ context->Exit(); ++ ++ return true; ++ } ++ ++ return false; ++} +diff --git a/src/cef/handlers/wam_cef_render_handler.h b/src/cef/handlers/wam_cef_render_handler.h +new file mode 100644 +index 0000000..4a05ed6 +--- /dev/null ++++ b/src/cef/handlers/wam_cef_render_handler.h +@@ -0,0 +1,54 @@ ++#ifndef CEF_HANDLERS_WAM_CEF_RENDER_HANDLER_H ++#define CEF_HANDLERS_WAM_CEF_RENDER_HANDLER_H ++ ++#include <map> ++#include <string> ++ ++#include "include/cef_app.h" ++#include "include/cef_render_process_handler.h" ++#include "include/cef_v8.h" ++ ++class WamCefRenderHandler : public CefApp, ++ public CefRenderProcessHandler, ++ public CefV8Handler { ++ public: ++ typedef std::map<std::pair<std::string, int>, ++ std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value>>> CallbackMap; ++ ++ WamCefRenderHandler(); ++ ++ CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override { ++ return this; ++ } ++ ++ void OnContextCreated(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefRefPtr<CefV8Context> context) override; ++ ++ ++ void OnContextReleased(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefRefPtr<CefV8Context> context) override; ++ ++ bool Execute(const CefString& name, ++ CefRefPtr<CefV8Value> object, ++ const CefV8ValueList& arguments, ++ CefRefPtr<CefV8Value>& retval, ++ CefString& exception) override; ++ ++ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, ++ CefRefPtr<CefFrame> frame, ++ CefProcessId source_process, ++ CefRefPtr<CefProcessMessage> message) override; ++ ++ void Start(const std::string &app_id); ++ void GetApplications(bool only_graphical, CefRefPtr<CefV8Value> callback); ++ ++ private: ++ IMPLEMENT_REFCOUNTING(WamCefRenderHandler); ++ DISALLOW_COPY_AND_ASSIGN(WamCefRenderHandler); ++ ++ CallbackMap callback_map_; ++}; ++ ++#endif // CEF_HANDLERS_WAM_CEF_RENDER_HANDLER_H +diff --git a/src/cef/platform_module_factory_cef.cc b/src/cef/platform_module_factory_cef.cc +new file mode 100644 +index 0000000..e225b9d +--- /dev/null ++++ b/src/cef/platform_module_factory_cef.cc +@@ -0,0 +1,31 @@ ++#include "platform_module_factory_cef.h" ++ ++#include "device_info_cef.h" ++#include "service_sender.h" ++#include "web_app_manager_config.h" ++#include "web_process_manager.h" ++ ++PlatformModuleFactoryCEF::PlatformModuleFactoryCEF() { ++ PrepareRenderingContext(); ++} ++ ++std::unique_ptr<ServiceSender> ++PlatformModuleFactoryCEF::CreateServiceSender() { ++ return nullptr; ++} ++ ++std::unique_ptr<WebProcessManager> ++PlatformModuleFactoryCEF::CreateWebProcessManager() { ++ return nullptr; ++} ++ ++std::unique_ptr<DeviceInfo> PlatformModuleFactoryCEF::CreateDeviceInfo() { ++ return std::make_unique<DeviceInfoCEF>(); ++} ++ ++std::unique_ptr<WebAppManagerConfig> ++PlatformModuleFactoryCEF::CreateWebAppManagerConfig() { ++ return std::unique_ptr<WebAppManagerConfig>(new WebAppManagerConfig()); ++} ++ ++void PlatformModuleFactoryCEF::PrepareRenderingContext() {} +diff --git a/src/cef/platform_module_factory_cef.h b/src/cef/platform_module_factory_cef.h +new file mode 100644 +index 0000000..5015dda +--- /dev/null ++++ b/src/cef/platform_module_factory_cef.h +@@ -0,0 +1,27 @@ ++#ifndef CEF_PLATFORM_MODULE_FACTORY_CEF_H_ ++#define CEF_PLATFORM_MODULE_FACTORY_CEF_H_ ++ ++#include <memory> ++ ++#include "platform_module_factory.h" ++ ++class ServiceSender; ++class WebProcessManager; ++class DeviceInfo; ++class WebAppManagerConfig; ++ ++class PlatformModuleFactoryCEF : public PlatformModuleFactory { ++ public: ++ PlatformModuleFactoryCEF(); ++ ++ protected: ++ std::unique_ptr<ServiceSender> CreateServiceSender() override; ++ std::unique_ptr<WebProcessManager> CreateWebProcessManager() override; ++ std::unique_ptr<DeviceInfo> CreateDeviceInfo() override; ++ std::unique_ptr<WebAppManagerConfig> CreateWebAppManagerConfig() override; ++ ++ private: ++ void PrepareRenderingContext(); ++}; ++ ++#endif // CEF_PLATFORM_MODULE_FACTORY_CEF_H_ +diff --git a/src/cef/plugin/web_app_cef.cc b/src/cef/plugin/web_app_cef.cc +new file mode 100644 +index 0000000..f57212b +--- /dev/null ++++ b/src/cef/plugin/web_app_cef.cc +@@ -0,0 +1,172 @@ ++#include "web_app_cef.h" ++ ++#include "include/base/cef_callback.h" ++#include "include/views/cef_display.h" ++#include "include/wrapper/cef_closure_task.h" ++ ++#include "web_page_cef.h" ++ ++WebAppCEF::WebAppCEF(std::shared_ptr<ApplicationDescription> app_desc) { ++ SetAppDescription(app_desc); ++} ++ ++WebAppCEF::~WebAppCEF() {} ++ ++void WebAppCEF::Init(int width, ++ int height, ++ AglShellSurfaceType surface_type, ++ AglShellPanelEdge panel_type) { ++ ApplicationDescription* app_desc = GetAppDescription(); ++ std::string app_id = app_desc->Id(); ++ ++ if (!IsReady()) { ++ return; ++ } ++ ++ surface_type_ = surface_type; ++ panel_type_ = panel_type; ++ ++ switch (surface_type_) { ++ case AglShellSurfaceType::kBackground: ++ window_->AglSetBackGroundApp(); ++ window_->AglSetAppReady(); ++ break; ++ case AglShellSurfaceType::kPanel: ++ window_->AglSetPanelApp(static_cast<int>(panel_type_)); ++ break; ++ case AglShellSurfaceType::kNone: ++ surface_type_ = AglShellSurfaceType::kNone; ++ CefPostDelayedTask( ++ TID_UI, ++ base::BindOnce(&WebAppCEF::DelayedActivate, this), ++ 500); ++ break; ++ } ++} ++ ++void WebAppCEF::TryInitialize() { ++ ApplicationDescription* app_desc = GetAppDescription(); ++ ++ if (!IsReady()) { ++ CefPostDelayedTask( ++ TID_UI, ++ base::BindOnce(&WebAppCEF::TryInitialize, this), ++ 500); ++ return; ++ // TODO: add a maximum number of retries ++ } ++ ++ Init(app_desc->WidthOverride(), ++ app_desc->HeightOverride(), ++ app_desc->SurfaceType(), ++ app_desc->PanelType()); ++} ++ ++void WebAppCEF::Attach(WebPageBase* web_page) { ++ WebAppBase::Attach(web_page); ++ ++ WebPageCEF* web_page_cef = static_cast<WebPageCEF*>(Page()); ++ if (!web_page_cef) { ++ // TODO: handle error ++ return; ++ } ++ web_page_cef->SetWebApp(this); ++} ++ ++void WebAppCEF::OnWindowCreated(CefRefPtr<CefWindow> window) { ++ if (!browser_view_) { ++ return; ++ } ++ ++ window_ = window; ++ window_->AddChildView(browser_view_); ++ window_->Show(); ++ ++ TryInitialize(); ++} ++ ++CefRect WebAppCEF::GetDisplayBounds() const { ++ CefRefPtr<CefDisplay> display = CefDisplay::GetPrimaryDisplay(); ++ CefRect display_bounds; ++ if (display) { ++ display_bounds = display->GetBounds(); ++ } ++ return display_bounds; ++} ++ ++CefSize WebAppCEF::GetPreferredSize(CefRefPtr<CefView> view) { ++ return CefSize(width_override_, height_override_); ++} ++ ++CefRect WebAppCEF::GetInitialBounds(CefRefPtr<CefWindow> window) { ++ return CefRect(0, 0, width_override_, height_override_); ++} ++ ++void WebAppCEF::SendAglReady() { ++ // Empty because it's called on Init() ++} ++ ++void WebAppCEF::SetAglAppId(const char* app_id) { ++ if (!window_) { ++ return; ++ } ++ window_->SetTitle(app_id); ++ window_->AglSetAppId(app_id); ++} ++ ++void WebAppCEF::SendAglActivate(const char* app_id) { ++ if (!window_) { ++ return; ++ } ++ window_->AglActivateApp(app_id); ++} ++ ++void WebAppCEF::Resize(int width, int height) { ++ if (!window_) { ++ return; ++ } ++ window_->SetSize(CefSize(width, height)); ++} ++ ++bool WebAppCEF::IsReady() const { ++ return window_ != nullptr; ++} ++ ++void WebAppCEF::Hide(bool forced_hide) { ++ if (!window_) { ++ return; ++ } ++ window_->Hide(); ++} ++ ++bool WebAppCEF::HideWindow() { ++ if (!window_) { ++ return false; ++ } ++ window_->Hide(); ++ return true; ++} ++ ++void WebAppCEF::Raise() { ++ if (!window_) { ++ return; ++ } ++ window_->BringToTop(); ++} ++ ++void WebAppCEF::DelayedActivate() { ++ ApplicationDescription* app_desc = GetAppDescription(); ++ SendAglActivate(app_desc->Id().c_str()); ++} ++ ++void WebAppCEF::Relaunch(const std::string& args, ++ const std::string& launching_app_id) { ++ if (!window_) { ++ return; ++ } ++ ++ ApplicationDescription* app_desc = GetAppDescription(); ++ std::string app_id = app_desc->Id(); ++ ++ SendAglActivate(app_id.c_str()); ++} +diff --git a/src/cef/plugin/web_app_cef.h b/src/cef/plugin/web_app_cef.h +new file mode 100644 +index 0000000..57145cf +--- /dev/null ++++ b/src/cef/plugin/web_app_cef.h +@@ -0,0 +1,95 @@ ++#ifndef CEF_PLUGIN_WEB_APP_CEF_H ++#define CEF_PLUGIN_WEB_APP_CEF_H ++ ++#include <cstdint> ++#include <memory> ++ ++#include "web_app_base.h" ++ ++#include "include/views/cef_window.h" ++#include "include/views/cef_browser_view.h" ++#include "include/views/cef_window_delegate.h" ++ ++#include "application_description.h" ++ ++class WebAppCEF : public WebAppBase, public CefWindowDelegate { ++ public: ++ WebAppCEF(std::shared_ptr<ApplicationDescription> app_desc); ++ ++ ~WebAppCEF(); ++ ++ virtual void Init(int width, ++ int height, ++ AglShellSurfaceType surface_type, ++ AglShellPanelEdge panel_type) override; ++ ++ void SuspendAppRendering() override {} ++ void ResumeAppRendering() override {} ++ bool IsFocused() const override { return false; } ++ void Resize(int width, int height) override; ++ bool IsActivated() const override { return false; } ++ bool IsMinimized() override { return false; } ++ bool IsNormal() override { return true; } ++ void OnStageActivated() override {} ++ void OnStageDeactivated() override {} ++ void DoAttach() override {} ++ void ConfigureWindow(const std::string& type) override {} ++ void SetWindowProperty(const std::string& name, ++ const std::string& value) override {} ++ void PlatformBack() override {} ++ void SetCursor(const std::string& cursor_arg, ++ int hotspot_x, ++ int hotspot_y) override {} ++ void SetInputRegion(const Json::Value& json_doc) override {} ++ void SetKeyMask(const Json::Value& json_doc) override {} ++ void Hide(bool forced_hide = false) override; ++ void Focus() override {} ++ void Unfocus() override {} ++ void SetOpacity(float opacity) override {} ++ void Raise() override; ++ void GoBackground() override {} ++ void DoPendingRelaunch() override {} ++ void DeleteSurfaceGroup() override {} ++ void DoClose() override {} ++ void SetUseVirtualKeyboard(const bool enable) override {} ++ bool HideWindow() override; ++ ++ void SendAglReady() override; ++ void SendAglActivate(const char* app_id) override; ++ void SetAglAppId(const char* app_id) override; ++ ++ void Attach(WebPageBase* web_page) override; ++ ++ void Relaunch(const std::string& args, ++ const std::string& launching_app_id) override; ++ ++ void SetBrowserView(CefRefPtr<CefBrowserView> browser_view) { ++ browser_view_ = browser_view; ++ } ++ ++ virtual bool IsReady() const; ++ ++ // CEF overrides ++ void OnWindowCreated(CefRefPtr<CefWindow> window) override; ++ CefSize GetPreferredSize(CefRefPtr<CefView> view) override; ++ CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override; ++ bool IsFrameless(CefRefPtr<CefWindow> window) override { return true; } ++ ++ protected: ++ void TryInitialize(); ++ void DelayedActivate(); ++ ++ CefRect GetDisplayBounds() const; ++ ++ CefRefPtr<CefBrowserView> browser_view_; ++ CefRefPtr<CefWindow> window_; ++ AglShellSurfaceType surface_type_; ++ AglShellPanelEdge panel_type_; ++ uint32_t width_override_ = 0; ++ uint32_t height_override_ = 0; ++ ++ private: ++ IMPLEMENT_REFCOUNTING(WebAppCEF); ++}; ++ ++#endif // CEF_PLUGIN_WEB_APP_CEF_H +diff --git a/src/cef/plugin/web_page_cef.cc b/src/cef/plugin/web_page_cef.cc +new file mode 100644 +index 0000000..32c6e89 +--- /dev/null ++++ b/src/cef/plugin/web_page_cef.cc +@@ -0,0 +1,48 @@ ++#include "web_page_cef.h" ++#include "application_description.h" ++ ++#include "include/views/cef_window.h" ++ ++#include "wam_cef_client.h" ++ ++WebPageCEF::WebPageCEF(std::shared_ptr<ApplicationDescription> app_desc, const std::string& url) ++ : url_{url} { ++ SetApplicationDescription(app_desc); ++} ++ ++WebPageCEF::~WebPageCEF() {} ++ ++void WebPageCEF::LoadUrl(const std::string& url) { ++ CefBrowserSettings browser_settings; ++ browser_view_ = CefBrowserView::CreateBrowserView( ++ WamCefClient::GetInstance(), url, browser_settings, nullptr, nullptr, this); ++ ++ web_app_->SetBrowserView(browser_view_); ++ ++ ApplicationDescription* app_desc = GetAppDescription(); ++ CefWindow::CreateTopLevelWindowWithId(web_app_, app_desc->Id()); ++} ++ ++void WebPageCEF::LoadDefaultUrl() { ++ LoadUrl(url_); ++} ++ ++bool WebPageCEF::HasBeenShown() const { ++ if (!web_app_) { ++ return false; ++ } ++ ++ return web_app_->IsReady(); ++} ++ ++ ++void WebPageCEF::EvaluateJavaScript(const std::string& jsCode) { ++ /*if (!browser_view_) { ++ return; ++ } ++ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser(); ++ if (!browser) { ++ return; ++ } ++ browser->GetMainFrame()->ExecuteJavaScript(jsCode, url_, 0);*/ ++} +diff --git a/src/cef/plugin/web_page_cef.h b/src/cef/plugin/web_page_cef.h +new file mode 100644 +index 0000000..f62c223 +--- /dev/null ++++ b/src/cef/plugin/web_page_cef.h +@@ -0,0 +1,69 @@ ++#ifndef CEF_PLUGIN_WEB_PAGE_CEF_H ++#define CEF_PLUGIN_WEB_PAGE_CEF_H ++ ++#include <memory> ++ ++#include "web_page_base.h" ++#include "web_app_cef.h" ++ ++#include "include/views/cef_browser_view_delegate.h" ++ ++class WebPageCEF : public WebPageBase, ++ public CefBrowserViewDelegate { ++ public: ++ WebPageCEF(std::shared_ptr<ApplicationDescription> app_desc, const std::string& url); ++ ~WebPageCEF() override; ++ ++ void Init() override {} ++ void* GetWebContents() override { return nullptr; } ++ ++ wam::Url Url() const override { return wam::Url(""); } ++ std::string FailedUrl() const override { return ""; } ++ void LoadUrl(const std::string& url) override; ++ int Progress() const override { return 0; } ++ bool HasBeenShown() const override; ++ void SetPageProperties() override {} ++ void SetPreferredLanguages(const std::string& language) override {} ++ void SetDefaultFont(const std::string& font) override {} ++ void ReloadDefaultPage() override {} ++ void Reload() override {} ++ void SetVisibilityState(WebPageVisibilityState visibility_state) override {} ++ void SetFocus(bool focus) override {} ++ std::string Title() override { return ""; } ++ bool CanGoBack() override { return false; } ++ void CloseVkb() override {} ++ void HandleDeviceInfoChanged(const std::string& device_info) override {} ++ void EvaluateJavaScript(const std::string& jsCode) override; ++ void EvaluateJavaScriptInAllFrames(const std::string& js_code, ++ const char* method = {}) override {} ++ uint32_t GetWebProcessProxyID() override { return 0; } ++ uint32_t GetWebProcessPID() const override { return 0; } ++ void CreatePalmSystem(WebAppBase* app) override {} ++ ++ void SuspendWebPageAll() override {} ++ void ResumeWebPageAll() override {} ++ void SuspendWebPageMedia() override {} ++ void ResumeWebPageMedia() override {} ++ void ResumeWebPagePaintingAndJSExecution() override {} ++ void ForwardEvent(void* event) override {} ++ ++ void SuspendWebPagePaintingAndJSExecution() override {} ++ ++ void SetWebApp(CefRefPtr<WebAppCEF> web_app) { web_app_ = web_app; } ++ ++ protected: ++ void LoadDefaultUrl() override; ++ void AddUserScript(const std::string& script) override {} ++ void AddUserScriptUrl(const wam::Url& url) override {} ++ void LoadErrorPage(int error_code) override {} ++ void RecreateWebView() override {} ++ ++ private: ++ IMPLEMENT_REFCOUNTING(WebPageCEF); ++ ++ CefRefPtr<CefBrowserView> browser_view_; ++ CefRefPtr<WebAppCEF> web_app_; ++ std::string url_; ++}; ++ ++#endif // CEF_PLUGIN_WEB_PAGE_CEF_H +diff --git a/src/cef/service/CMakeLists.txt b/src/cef/service/CMakeLists.txt +new file mode 100644 +index 0000000..763b527 +--- /dev/null ++++ b/src/cef/service/CMakeLists.txt +@@ -0,0 +1,64 @@ ++project(WebAppMgrService VERSION 1.0.0 DESCRIPTION "Web Application Manager cli helper") ++ ++find_package(gRPC REQUIRED) ++find_program(GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin REQUIRED) ++find_package(Protobuf REQUIRED) ++find_package(Threads) ++ ++set(WAM_GRPC_LIB_NAME ${PROJECT_NAME}-grpc) ++set(APPLAUNCHER_LIB_NAME WamAppLauncher-grpc) ++ ++set(WAM_GRPC_LIBS ++ protobuf::libprotobuf ++ gRPC::grpc ++ gRPC::grpc++ ++ gRPC::grpc++_reflection ++) ++set(WAM_SERVICE_LIBS ++ ${WAM_GRPC_LIBS} ++ ${WAM_GRPC_LIB_NAME} ++ ${APPLAUNCHER_LIB_NAME} ++ libcef_lib ++ libcef_dll_wrapper ++) ++set(WAM_GRPC_INCLUDE_DIRS ++ ${CMAKE_CURRENT_SOURCE_DIR} ++ ${CMAKE_CURRENT_BINARY_DIR} ++) ++set(WAM_SERVICE_INCLUDE_DIRS ++ ${CEF_INCLUDE_PATH} ++ ${WAM_ROOT_SOURCE_DIR}/core ++ ${WAM_ROOT_SOURCE_DIR}/util ++) ++set(SOURCES ++ applauncher_client_grpc.cc ++ web_app_manager_client_grpc.cc ++ web_app_manager_service_grpc.cc ++) ++set(HEADERS ++ applauncher_client_grpc.h ++ web_app_manager_client_grpc.h ++ web_app_manager_service_grpc.h ++) ++ ++ ++macro(add_wam_grpc_lib target proto) ++ add_library(${target} SHARED ${proto}) ++ target_include_directories(${target} PUBLIC ${WAM_GRPC_INCLUDE_DIRS}) ++ target_link_libraries(${target} PUBLIC ${WAM_GRPC_LIBS}) ++ set_target_properties(${target} PROPERTIES VERSION 1.0.0 SOVERSION 1.0) ++ protobuf_generate(TARGET ${target} LANGUAGE cpp APPEND_PATH) ++ protobuf_generate(TARGET ${target} LANGUAGE grpc APPEND_PATH GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${GRPC_CPP_PLUGIN_EXECUTABLE}") ++ install(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++endmacro(add_wam_grpc_lib) ++ ++add_wam_grpc_lib(${WAM_GRPC_LIB_NAME} wam_ipc.proto) ++add_wam_grpc_lib(${APPLAUNCHER_LIB_NAME} applauncher.proto) ++ ++add_library(${PROJECT_NAME} SHARED ${HEADERS} ${SOURCES}) ++set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1.0) ++add_dependencies(${PROJECT_NAME} ${WAM_GRPC_LIB_NAME}) ++target_include_directories(${PROJECT_NAME} PUBLIC ${WAM_SERVICE_INCLUDE_DIRS}) ++target_link_libraries(${PROJECT_NAME} PUBLIC ${WAM_SERVICE_LIBS}) ++install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +diff --git a/src/cef/service/applauncher.proto b/src/cef/service/applauncher.proto +new file mode 100644 +index 0000000..0b8e0fc +--- /dev/null ++++ b/src/cef/service/applauncher.proto +@@ -0,0 +1,50 @@ ++syntax = "proto3"; ++ ++package automotivegradelinux; ++ ++service AppLauncher { ++ rpc StartApplication(StartRequest) returns (StartResponse) {} ++ rpc ListApplications(ListRequest) returns (ListResponse) {} ++ rpc GetStatusEvents(StatusRequest) returns (stream StatusResponse) {} ++} ++ ++message StartRequest { ++ string id = 1; ++} ++ ++message StartResponse { ++ bool status = 1; ++ string message = 2; ++} ++ ++message ListRequest { ++} ++ ++message ListResponse { ++ repeated AppInfo apps = 1; ++} ++ ++message AppInfo { ++ string id = 1; ++ string name = 2; ++ string icon_path = 3; ++} ++ ++message StatusRequest { ++} ++ ++message AppStatus { ++ string id = 1; ++ string status = 2; ++} ++ ++// Future-proofing for e.g. potentially signaling a list refresh ++message LauncherStatus { ++} ++ ++message StatusResponse { ++ oneof status { ++ AppStatus app = 1; ++ LauncherStatus launcher = 2; ++ } ++} +diff --git a/src/cef/service/applauncher_client_grpc.cc b/src/cef/service/applauncher_client_grpc.cc +new file mode 100644 +index 0000000..f704742 +--- /dev/null ++++ b/src/cef/service/applauncher_client_grpc.cc +@@ -0,0 +1,58 @@ ++#include "applauncher_client_grpc.h" ++ ++#include <grpcpp/ext/proto_server_reflection_plugin.h> ++#include <grpcpp/grpcpp.h> ++#include <grpcpp/health_check_service_interface.h> ++ ++#include "include/cef_parser.h" ++ ++AppLauncherClientGRPC::AppLauncherClientGRPC() ++ : stub_{MakeStub()} { ++} ++ ++std::unique_ptr<automotivegradelinux::AppLauncher::Stub>AppLauncherClientGRPC::MakeStub() const { ++ return automotivegradelinux::AppLauncher::NewStub(grpc::CreateChannel("localhost:50052", ++ grpc::InsecureChannelCredentials())); ++} ++ ++void AppLauncherClientGRPC::Start(const std::string& app_id) { ++ automotivegradelinux::StartRequest request; ++ request.set_id(app_id); ++ ++ grpc::ClientContext context; ++ automotivegradelinux::StartResponse response; ++ ++ grpc::Status status = stub_->StartApplication(&context, request, &response); ++} ++ ++void AppLauncherClientGRPC::GetApplications(CefRefPtr<CefBrowser> browser, bool only_graphical) { ++ automotivegradelinux::ListRequest request; ++ automotivegradelinux::ListResponse response; ++ grpc::ClientContext context; ++ ++ grpc::Status status = stub_->ListApplications(&context, request, &response); ++ if (!status.ok()) { ++ return; ++ } ++ ++ CefRefPtr<CefListValue> apps_list = CefListValue::Create(); ++ for (int i = 0; i < response.apps_size(); i++) { ++ automotivegradelinux::AppInfo app_info = response.apps(i); ++ CefRefPtr<CefDictionaryValue> app_info_dict = CefDictionaryValue::Create(); ++ app_info_dict->SetString("id", app_info.id()); ++ app_info_dict->SetString("name", app_info.name()); ++ app_info_dict->SetString("icon", app_info.icon_path()); ++ apps_list->SetDictionary(i, app_info_dict); ++ } ++ ++ CefRefPtr<CefValue> apps_list_value = CefValue::Create(); ++ apps_list_value->SetList(apps_list); ++ std::string response_string = CefWriteJSON(apps_list_value, JSON_WRITER_DEFAULT); ++ ++ // send the response to renderer process ++ CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create("get_applications"); ++ CefRefPtr<CefListValue> args = message->GetArgumentList(); ++ args->SetString(0, response_string); ++ browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, message); ++} ++ +diff --git a/src/cef/service/applauncher_client_grpc.h b/src/cef/service/applauncher_client_grpc.h +new file mode 100644 +index 0000000..4a3f289 +--- /dev/null ++++ b/src/cef/service/applauncher_client_grpc.h +@@ -0,0 +1,24 @@ ++#ifndef CEF_SERVICE_APPLAUNCHER_CLIENT_GRPC_H ++#define CEF_SERVICE_APPLAUNCHER_CLIENT_GRPC_H ++ ++#include <string> ++ ++#include "applauncher.grpc.pb.h" ++ ++#include "include/cef_browser.h" ++ ++class AppLauncherClientGRPC { ++ public: ++ ++ AppLauncherClientGRPC(); ++ ++ void Start(const std::string& app_id); ++ void GetApplications(CefRefPtr<CefBrowser> browser, bool only_graphical); ++ ++ private: ++ std::unique_ptr<automotivegradelinux::AppLauncher::Stub> MakeStub() const; ++ ++ std::unique_ptr<automotivegradelinux::AppLauncher::Stub> stub_; ++}; ++ ++#endif // CEF_SERVICE_APPLAUNCHER_CLIENT_GRPC_H +diff --git a/src/cef/service/wam_ipc.proto b/src/cef/service/wam_ipc.proto +new file mode 100644 +index 0000000..313de8f +--- /dev/null ++++ b/src/cef/service/wam_ipc.proto +@@ -0,0 +1,22 @@ ++syntax = "proto3"; ++import "google/protobuf/empty.proto"; ++package wam_ipc; ++ ++service WebAppManagerService { ++ rpc Launch(LaunchRequest) returns (google.protobuf.Empty) {} ++ rpc Activate(ActivateRequest) returns (google.protobuf.Empty) {} ++ rpc Kill(KillRequest) returns (google.protobuf.Empty) {} ++} ++ ++message LaunchRequest { ++ string app_id = 1; ++ string uri = 2; ++} ++ ++message ActivateRequest { ++ string app_id = 1; ++} ++ ++message KillRequest { ++ string app_id = 1; ++} +diff --git a/src/cef/service/web_app_manager_client_grpc.cc b/src/cef/service/web_app_manager_client_grpc.cc +new file mode 100644 +index 0000000..8529868 +--- /dev/null ++++ b/src/cef/service/web_app_manager_client_grpc.cc +@@ -0,0 +1,42 @@ ++#include "web_app_manager_client_grpc.h" ++ ++#include <grpcpp/ext/proto_server_reflection_plugin.h> ++#include <grpcpp/grpcpp.h> ++#include <grpcpp/health_check_service_interface.h> ++ ++const char kDefaultGrpcServiceAddress[] = "127.0.0.1:15000"; ++ ++WebAppManagerClientGRPC::WebAppManagerClientGRPC() { ++ auto channel = grpc::CreateChannel(kDefaultGrpcServiceAddress, ++ grpc::InsecureChannelCredentials()); ++ stub_ = wam_ipc::WebAppManagerService::NewStub(channel); ++} ++ ++bool WebAppManagerClientGRPC::Launch(const LaunchParams& params) { ++ wam_ipc::LaunchRequest request; ++ request.set_app_id(params.app_id); ++ request.set_uri(params.uri); ++ ++ grpc::ClientContext context; ++ google::protobuf::Empty reply; ++ grpc::Status status = stub_->Launch(&context, request, &reply); ++ return status.ok(); ++} ++ ++bool WebAppManagerClientGRPC::Activate(const std::string& app_id) { ++ grpc::ClientContext context; ++ google::protobuf::Empty reply; ++ wam_ipc::ActivateRequest request; ++ request.set_app_id(app_id); ++ grpc::Status status = stub_->Activate(&context, request, &reply); ++ return status.ok(); ++} ++ ++bool WebAppManagerClientGRPC::Kill(const std::string& app_id) { ++ grpc::ClientContext context; ++ google::protobuf::Empty reply; ++ wam_ipc::KillRequest request; ++ request.set_app_id(app_id); ++ grpc::Status status = stub_->Kill(&context, request, &reply); ++ return status.ok(); ++} +diff --git a/src/cef/service/web_app_manager_client_grpc.h b/src/cef/service/web_app_manager_client_grpc.h +new file mode 100644 +index 0000000..9c4be70 +--- /dev/null ++++ b/src/cef/service/web_app_manager_client_grpc.h +@@ -0,0 +1,23 @@ ++#ifndef CEF_SERVICE_WEB_APP_MANAGER_CLIENT_GRPC_H ++#define CEF_SERVICE_WEB_APP_MANAGER_CLIENT_GRPC_H ++ ++#include "wam_ipc.grpc.pb.h" ++ ++class WebAppManagerClientGRPC { ++ public: ++ struct LaunchParams { ++ std::string app_id; ++ std::string uri; ++ }; ++ ++ WebAppManagerClientGRPC(); ++ bool Launch(const LaunchParams& params); ++ bool Activate(const std::string& app_id); ++ bool Kill(const std::string& app_id); ++ ++ private: ++ std::unique_ptr<wam_ipc::WebAppManagerService::Stub> stub_; ++}; ++ ++#endif // CEF_SERVICE_WEB_APP_MANAGER_CLIENT_GRPC_H ++ +diff --git a/src/cef/service/web_app_manager_service_grpc.cc b/src/cef/service/web_app_manager_service_grpc.cc +new file mode 100644 +index 0000000..52de924 +--- /dev/null ++++ b/src/cef/service/web_app_manager_service_grpc.cc +@@ -0,0 +1,382 @@ ++// Copyright (c) 2018-2022 LG Electronics, Inc. ++// ++// 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. ++// ++// SPDX-License-Identifier: Apache-2.0 ++ ++#include "web_app_manager_service_grpc.h" ++ ++#include <grpcpp/ext/proto_server_reflection_plugin.h> ++#include <grpcpp/grpcpp.h> ++#include <grpcpp/health_check_service_interface.h> ++#include <pthread.h> ++#include <sys/file.h> ++#include <sys/un.h> ++#include <unistd.h> ++#include <algorithm> ++#include <cassert> ++#include <climits> ++#include <cstdlib> ++#include <exception> ++#include <fstream> ++#include <iostream> ++#include <set> ++#include <sstream> ++ ++#include <json/value.h> ++ ++#include "log_manager.h" ++#include "utils.h" ++#include "wam_ipc.grpc.pb.h" ++#include "web_app_base.h" ++#include "web_app_manager.h" ++ ++namespace { ++const char kDefaultGrpcServiceAddress[] = "127.0.0.1:15000"; ++} // namespace ++ ++class WamIPCLockFile { ++ public: ++ WamIPCLockFile() { ++ const char* runtime_dir; ++ if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) { ++ LOG_DEBUG("Failed to retrieve XDG_RUNTIME_DIR, falling back to /tmp"); ++ runtime_dir = "/tmp"; ++ } ++ lock_file_ = std::string(runtime_dir); ++ lock_file_.append("/wamipc.lock"); ++ } ++ ++ ~WamIPCLockFile() { ++ if (lock_fd_ != -1) ++ ReleaseLock(lock_fd_); ++ if (lock_fd_ != -1) ++ close(lock_fd_); ++ } ++ ++ bool CreateAndLock() { ++ lock_fd_ = OpenLockFile(); ++ if (!AcquireLock(lock_fd_)) { ++ LOG_DEBUG("Failed to lock file %d", lock_fd_); ++ return false; ++ } ++ return true; ++ } ++ ++ bool OwnsLock() const { return lock_fd_ != -1; } ++ ++ bool TryAcquireLock() { ++ int fd = OpenLockFile(); ++ if (fd != -1) { ++ if (AcquireLock(fd)) { ++ ReleaseLock(fd); ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ private: ++ int OpenLockFile() { ++ int fd = open(lock_file_.c_str(), O_CREAT | O_TRUNC, S_IRWXU); ++ if (fd == -1) { ++ LOG_DEBUG("Failed to open lock file descriptor"); ++ return fd; ++ } ++ ++ int flags = fcntl(fd, F_GETFD); ++ if (flags == -1) ++ LOG_DEBUG("Could not get flags for lock file %d", fd); ++ ++ flags |= FD_CLOEXEC; ++ ++ if (fcntl(fd, F_SETFD, flags) == -1) ++ LOG_DEBUG("Could not set flags for lock file %d", fd); ++ ++ return fd; ++ } ++ ++ bool AcquireLock(int fd) { ++ if (flock(fd, LOCK_EX | LOCK_NB) != 0) ++ return false; ++ return true; ++ } ++ ++ void ReleaseLock(int fd) { flock(fd, LOCK_UN); } ++ ++ std::string lock_file_; ++ int lock_fd_ = -1; ++}; ++ ++class GrpcServiceImpl final ++ : public wam_ipc::WebAppManagerService::CallbackService { ++ grpc::ServerUnaryReactor* Launch(grpc::CallbackServerContext* context, ++ const ::wam_ipc::LaunchRequest* request, ++ google::protobuf::Empty* /*response*/) { ++ WebAppManagerServiceGRPC::LaunchParams launch_params; ++ launch_params.app_id = request->app_id(); ++ launch_params.uri = request->uri(); ++ launch_params.width = 0; ++ launch_params.height = 0; ++ ++ WebAppManagerServiceGRPC::Instance()->LaunchOnIdle(launch_params); ++ ++ grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); ++ reactor->Finish(grpc::Status::OK); ++ return reactor; ++ } ++ grpc::ServerUnaryReactor* Activate(grpc::CallbackServerContext* context, ++ const ::wam_ipc::ActivateRequest* request, ++ google::protobuf::Empty* /*response*/) { ++ WebAppManagerServiceGRPC::Instance()->SendEventOnIdle(kActivateEvent, ++ request->app_id()); ++ grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); ++ reactor->Finish(grpc::Status::OK); ++ return reactor; ++ } ++ grpc::ServerUnaryReactor* Kill(grpc::CallbackServerContext* context, ++ const ::wam_ipc::KillRequest* request, ++ google::protobuf::Empty* /*response*/) { ++ WebAppManagerServiceGRPC::Instance()->SendEventOnIdle(kKilledApp, ++ request->app_id()); ++ grpc::ServerUnaryReactor* reactor = context->DefaultReactor(); ++ reactor->Finish(grpc::Status::OK); ++ return reactor; ++ } ++}; ++ ++WebAppManagerServiceGRPC::WebAppManagerServiceGRPC() ++ : lock_file_(std::make_unique<WamIPCLockFile>()) {} ++ ++WebAppManagerServiceGRPC* WebAppManagerServiceGRPC::Instance() { ++ static WebAppManagerServiceGRPC* srv = new WebAppManagerServiceGRPC(); ++ return srv; ++} ++ ++bool WebAppManagerServiceGRPC::InitializeAsHostService() { ++ return lock_file_->CreateAndLock(); ++} ++ ++bool WebAppManagerServiceGRPC::IsHostServiceRunning() { ++ return !lock_file_->TryAcquireLock(); ++} ++ ++void* RunGrpcService(void*) { ++ std::string server_address(kDefaultGrpcServiceAddress); ++ GrpcServiceImpl service; ++ ++ grpc::EnableDefaultHealthCheckService(true); ++ grpc::reflection::InitProtoReflectionServerBuilderPlugin(); ++ ++ grpc::ServerBuilder builder; ++ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); ++ builder.RegisterService(&service); ++ ++ std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); ++ std::cout << "Server listening on " << server_address << std::endl; ++ server->Wait(); ++ ++ return nullptr; ++} ++ ++bool WebAppManagerServiceGRPC::StartService() { ++ if (lock_file_->OwnsLock()) { ++ pthread_t thread_id; ++ if (pthread_create(&thread_id, nullptr, RunGrpcService, nullptr) < 0) { ++ perror("Could not create thread"); ++ LOG_DEBUG("Could not create thread..."); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++void WebAppManagerServiceGRPC::LaunchOnIdle(const LaunchParams& params) { ++ auto launch_params = std::make_unique<LaunchParams>(params); ++ ++ auto* timer = ++ new OneShotTimerWithData<WebAppManagerServiceGRPC, LaunchParams>(); ++ timer->Start(0, this, &WebAppManagerServiceGRPC::OnLaunchApp, ++ std::move(launch_params)); ++} ++ ++void WebAppManagerServiceGRPC::SendEventOnIdle(const std::string& event, ++ const std::string& app_id) { ++ auto event_data = std::make_unique<EventData>(); ++ event_data->app_id = app_id; ++ auto* timer = new OneShotTimerWithData<WebAppManagerServiceGRPC, EventData>(); ++ if (event == kActivateEvent) ++ timer->Start(0, this, &WebAppManagerServiceGRPC::OnActivateEvent, ++ std::move(event_data)); ++ else if (event == kDeactivateEvent) ++ timer->Start(0, this, &WebAppManagerServiceGRPC::OnDeactivateEvent, ++ std::move(event_data)); ++ else if (event == kKilledApp) ++ timer->Start(1000, this, &WebAppManagerServiceGRPC::OnKillEvent, ++ std::move(event_data)); ++} ++ ++void WebAppManagerServiceGRPC::OnLaunchApp(LaunchParams* params) { ++ LOG_DEBUG("Triggering app start: %s", params->uri.c_str()); ++ if (!params->uri.empty()) { ++ if (params->uri.find("http://") == 0) { ++ LaunchStartupAppFromURL(params); ++ } else { ++ LaunchStartupAppFromJsonConfig(params); ++ } ++ } ++} ++ ++void WebAppManagerServiceGRPC::LaunchStartupAppFromJsonConfig( ++ LaunchParams* params) { ++ std::string configfile; ++ configfile.append(params->uri); ++ configfile.append("/appinfo.json"); ++ ++ Json::Value root; ++ Json::CharReaderBuilder builder; ++ JSONCPP_STRING errs; ++ ++ std::ifstream ifs; ++ ifs.open(configfile.c_str()); ++ ++ if (!parseFromStream(builder, ifs, &root, &errs)) { ++ LOG_DEBUG("Failed to parse %s configuration file", configfile.c_str()); ++ } ++ ++ root["folderPath"] = params->uri.c_str(); ++ ++ auto surface_obj = root["surface"]; ++ auto surface_type = surface_obj["type"].asString(); ++ if (surface_type == "background") { ++ root["surface_type"] = 1; // AglShellSurfaceType::kBackground; ++ } else if (surface_type == "panel") { ++ root["surface_type"] = 2; // AglShellSurfaceType::kPanel; ++ } else { ++ root["surface_type"] = 0; // AglShellSurfaceType::kNone; ++ } ++ ++ std::string app_desc = util::JsonToString(root); ++ std::string empty_params = "{}"; ++ std::string app_id = root["id"].asString(); ++ int err_code = 0; ++ std::string err_msg; ++ WebAppManagerService::OnLaunch(app_desc, empty_params, app_id, err_code, ++ err_msg); ++} ++ ++void WebAppManagerServiceGRPC::LaunchStartupAppFromURL(LaunchParams* params) { ++ LOG_DEBUG("WebAppManagerServiceGRPC::LaunchStartupAppFromURL"); ++ LOG_DEBUG(" url: %s", params->uri.c_str()); ++ Json::Value obj(Json::objectValue); ++ obj["id"] = params->app_id; ++ obj["version"] = "1.0"; ++ obj["vendor"] = "some vendor"; ++ obj["type"] = "web"; ++ obj["main"] = params->uri; ++ obj["title"] = "webapp"; ++ obj["uiRevision"] = "2"; ++ ++ obj["widthOverride"] = params->width; ++ obj["heightOverride"] = params->height; ++ ++ std::string app_desc = util::JsonToString(obj); ++ std::string app_id = params->app_id; ++ int err_code = 0; ++ std::string empty_params = "{}"; ++ std::string err_msg; ++ ++ LOG_DEBUG("Launching with appDesc=[%s]", app_desc.c_str()); ++ ++ WebAppManagerService::OnLaunch(app_desc, empty_params, app_id, err_code, ++ err_msg); ++ LOG_DEBUG("onLaunch: Done."); ++} ++ ++Json::Value WebAppManagerServiceGRPC::launchApp(const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::killApp(const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::pauseApp(const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::logControl(const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::setInspectorEnable( ++ const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::closeAllApps(const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::discardCodeCache( ++ const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::listRunningApps( ++ const Json::Value& request, ++ bool subscribed) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::getWebProcessSize( ++ const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::clearBrowsingData( ++ const Json::Value& request) { ++ return Json::Value(Json::objectValue); ++} ++ ++Json::Value WebAppManagerServiceGRPC::webProcessCreated( ++ const Json::Value& request, ++ bool subscribed) { ++ return Json::Value(Json::objectValue); ++} ++ ++void WebAppManagerServiceGRPC::OnActivateEvent(EventData* event_data) { ++ LOG_DEBUG("Activate app=%s", event_data->app_id.c_str()); ++ WebAppBase* web_app = ++ WebAppManager::Instance()->FindAppById(event_data->app_id); ++ if (web_app) { ++ web_app->OnStageActivated(); ++ web_app->SendAglActivate(event_data->app_id.c_str()); ++ } else { ++ LOG_DEBUG("Not found app=%s running", event_data->app_id.c_str()); ++ } ++} ++ ++void WebAppManagerServiceGRPC::OnDeactivateEvent(EventData* event_data) { ++ LOG_DEBUG("Dectivate app=%s", event_data->app_id.c_str()); ++ WebAppBase* web_app = ++ WebAppManager::Instance()->FindAppById(event_data->app_id); ++ if (web_app) ++ web_app->OnStageDeactivated(); ++} ++ ++void WebAppManagerServiceGRPC::OnKillEvent(EventData* event_data) { ++ LOG_DEBUG("Kill app=%s", event_data->app_id.c_str()); ++ WebAppManager::Instance()->OnKillApp(event_data->app_id, event_data->app_id); ++} +diff --git a/src/cef/service/web_app_manager_service_grpc.h b/src/cef/service/web_app_manager_service_grpc.h +new file mode 100644 +index 0000000..69ea0ed +--- /dev/null ++++ b/src/cef/service/web_app_manager_service_grpc.h +@@ -0,0 +1,85 @@ ++// Copyright (c) 2018-2022 LG Electronics, Inc. ++// ++// 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. ++// ++// SPDX-License-Identifier: Apache-2.0 ++ ++#ifndef CEF_SERVICE_WEB_APP_MANAGER_SERVICE_GRPC_H ++#define CEF_SERVICE_WEB_APP_MANAGER_SERVICE_GRPC_H ++ ++#include <memory> ++ ++#include "timer.h" ++#include "web_app_manager_service.h" ++ ++constexpr char kStartApp[] = "start-app"; ++constexpr char kKilledApp[] = "killed-app"; ++constexpr char kActivateEvent[] = "activate-event"; ++constexpr char kDeactivateEvent[] = "deactivate-event"; ++ ++class GrpcClient; ++class WamIPCLockFile; ++ ++class WebAppManagerServiceGRPC : public WebAppManagerService, ++ public TimerReceiver { ++ public: ++ struct LaunchParams { ++ std::string app_id; ++ std::string uri; ++ int width = 0; ++ int height = 0; ++ }; ++ ++ static WebAppManagerServiceGRPC* Instance(); ++ ++ bool InitializeAsHostService(); ++ bool IsHostServiceRunning(); ++ ++ void LaunchOnIdle(const LaunchParams& params); ++ void SendEventOnIdle(const std::string& event, const std::string& app_id); ++ ++ // WebAppManagerService ++ bool StartService() override; ++ Json::Value launchApp(const Json::Value& request) override; ++ Json::Value killApp(const Json::Value& request) override; ++ Json::Value pauseApp(const Json::Value& request) override; ++ Json::Value logControl(const Json::Value& request) override; ++ Json::Value setInspectorEnable(const Json::Value& request) override; ++ Json::Value closeAllApps(const Json::Value& request) override; ++ Json::Value discardCodeCache(const Json::Value& request) override; ++ Json::Value listRunningApps(const Json::Value& request, ++ bool subscribed) override; ++ Json::Value getWebProcessSize(const Json::Value& request) override; ++ Json::Value clearBrowsingData(const Json::Value& request) override; ++ Json::Value webProcessCreated(const Json::Value& request, ++ bool subscribed) override; ++ ++ void TriggerStartupApp(); ++ ++ private: ++ WebAppManagerServiceGRPC(); ++ ++ void OnLaunchApp(LaunchParams* launch_data); ++ void LaunchStartupAppFromJsonConfig(LaunchParams*); ++ void LaunchStartupAppFromURL(LaunchParams*); ++ struct EventData { ++ std::string app_id; ++ }; ++ void OnActivateEvent(EventData* event_data); ++ void OnDeactivateEvent(EventData* event_data); ++ void OnKillEvent(EventData* event_data); ++ ++ std::unique_ptr<WamIPCLockFile> lock_file_; ++}; ++ ++#endif // CEF_SERVICE_WEB_APP_MANAGER_SERVICE_GRPC_H +diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt +index 182f96a..41871b9 100644 +--- a/src/core/CMakeLists.txt ++++ b/src/core/CMakeLists.txt +@@ -18,6 +18,7 @@ project(WebAppMgrCore VERSION 1.0.0 DESCRIPTION "Core of the Web Application Man + + set(SOURCES + application_description.cc ++ application_installation_handler_stub.cc + device_info.cc + palm_system_base.cc + plugin_service.cc +@@ -44,7 +45,9 @@ set(SOURCES + set(HEADERS + agl_shell_types.h + application_description.h ++ application_installation_handler.h + device_info.h ++ memory_pressure_level.h + palm_system_base.h + platform_module_factory.h + plugin_service.h +@@ -95,6 +98,7 @@ set(CORE_INCLUDE_DIRS + set(CORE_LIBS + ${CHROMIUM_LDFLAGS} + ${GLIB_LDFLAGS} ++ ${JSONCPP_LDFLAGS} + ${PMLOGLIB_LDFLAGS} + Boost::filesystem + dl +diff --git a/src/core/application_description.cc b/src/core/application_description.cc +index 9b494fc..adbb7d8 100644 +--- a/src/core/application_description.cc ++++ b/src/core/application_description.cc +@@ -144,12 +144,49 @@ std::unique_ptr<ApplicationDescription> ApplicationDescription::FromJsonString( + auto app_desc = + std::unique_ptr<ApplicationDescription>(new ApplicationDescription()); + ++ + app_desc->surface_type_ = + static_cast<AglShellSurfaceType>(json_obj["surface_type"].asInt()); + app_desc->panel_type_ = + static_cast<AglShellPanelEdge>(json_obj["panel_type"].asInt()); + app_desc->width_override_ = json_obj["widthOverride"].asInt(); + app_desc->height_override_ = json_obj["heightOverride"].asInt(); ++ ++ // override previous values if the json config file contains ++ // a "surface" object with nested data ++ auto surface_obj = json_obj["surface"]; ++ if (!surface_obj.empty()) { ++ std::string surface_type = surface_obj["type"].asString(); ++ if (surface_type == "background") { ++ app_desc->surface_type_ = AglShellSurfaceType::kBackground; ++ } else if (surface_type == "panel") { ++ app_desc->surface_type_ = AglShellSurfaceType::kPanel; ++ } else { ++ app_desc->surface_type_ = AglShellSurfaceType::kNone; ++ } ++ ++ std::string panel_edge = surface_obj["panel_edge"].asString(); ++ if (panel_edge == "left") { ++ app_desc->panel_type_ = AglShellPanelEdge::kLeft; ++ } else if (panel_edge == "right") { ++ app_desc->panel_type_ = AglShellPanelEdge::kRight; ++ } else if (panel_edge == "top") { ++ app_desc->panel_type_ = AglShellPanelEdge::kTop; ++ } else if (panel_edge == "bottom") { ++ app_desc->panel_type_ = AglShellPanelEdge::kBottom; ++ } ++ ++ int width = 0; ++ if (!surface_obj["width"].empty()) ++ util::StrToInt(surface_obj["width"].asString(), width); ++ app_desc->width_override_ = width; ++ ++ int height = 0; ++ if (!surface_obj["height"].empty()) ++ util::StrToInt(surface_obj["height"].asString(), height); ++ app_desc->height_override_ = height; ++ } ++ + app_desc->transparency_ = json_obj["transparent"].asBool(); + auto vendor_extension = + json_obj.get("vendorExtension", Json::Value(Json::objectValue)); +diff --git a/src/core/application_installation_handler.h b/src/core/application_installation_handler.h +new file mode 100644 +index 0000000..054bc9d +--- /dev/null ++++ b/src/core/application_installation_handler.h +@@ -0,0 +1,12 @@ ++#ifndef CORE_APPLICATION_INSTALLATION_HANDLER_H_ ++#define CORE_APPLICATION_INSTALLATION_HANDLER_H_ ++ ++#include <string> ++ ++class ApplicationInstallationHandler { ++ public: ++ static void OnAppInstalled(const std::string& app_id); ++ static void OnAppRemoved(const std::string& app_id); ++}; ++ ++#endif // CORE_APPLICATION_INSTALLATION_HANDLER_H_ +\ No newline at end of file +diff --git a/src/core/application_installation_handler_stub.cc b/src/core/application_installation_handler_stub.cc +new file mode 100644 +index 0000000..016c7d2 +--- /dev/null ++++ b/src/core/application_installation_handler_stub.cc +@@ -0,0 +1,4 @@ ++#include "application_installation_handler.h" ++ ++void ApplicationInstallationHandler::OnAppInstalled(const std::string&) {} ++void ApplicationInstallationHandler::OnAppRemoved(const std::string&) {} +\ No newline at end of file +diff --git a/src/core/memory_pressure_level.h b/src/core/memory_pressure_level.h +new file mode 100644 +index 0000000..01c9316 +--- /dev/null ++++ b/src/core/memory_pressure_level.h +@@ -0,0 +1,6 @@ ++#ifndef CORE_MEMORY_PRESSURE_LEVEL_H_ ++#define CORE_MEMORY_PRESSURE_LEVEL_H_ ++ ++enum class MemoryPressureLevel { kNone, kLow, kCritical }; ++ ++#endif // CORE_MEMORY_PRESSURE_LEVEL_H_ +\ No newline at end of file +diff --git a/src/core/web_app_manager.cc b/src/core/web_app_manager.cc +index ca64ef1..42e8be7 100644 +--- a/src/core/web_app_manager.cc ++++ b/src/core/web_app_manager.cc +@@ -22,10 +22,9 @@ + #include <string> + + #include <json/value.h> +-#include "webos/application_installation_handler.h" +-#include "webos/public/runtime.h" + + #include "application_description.h" ++#include "application_installation_handler.h" + #include "base_check.h" + #include "device_info.h" + #include "log_manager.h" +@@ -63,8 +62,7 @@ WebAppManager::~WebAppManager() { + device_info_->Terminate(); + } + +-void WebAppManager::NotifyMemoryPressure( +- webos::WebViewBase::MemoryPressureLevel level) { ++void WebAppManager::NotifyMemoryPressure(MemoryPressureLevel level) { + std::list<const WebAppBase*> app_list = RunningApps(); + for (auto it = app_list.begin(); it != app_list.end(); ++it) { + const WebAppBase* app = *it; +@@ -72,15 +70,14 @@ void WebAppManager::NotifyMemoryPressure( + // critical (when system is on low or critical) because they will be killed + // anyway + if (app->IsActivated() && +- (!app->Page()->IsPreload() || +- level != webos::WebViewBase::MEMORY_PRESSURE_CRITICAL)) ++ (!app->Page()->IsPreload() || level != MemoryPressureLevel::kCritical)) + app->Page()->NotifyMemoryPressure(level); + else { + LOG_DEBUG( + "Skipping memory pressure handler for" + " instanceId(%s) appId(%s) isActivated(%d) isPreload(%d) Level(%d)", + app->InstanceId().c_str(), app->AppId().c_str(), app->IsActivated(), +- app->Page()->IsPreload(), level); ++ app->Page()->IsPreload(), static_cast<int>(level)); + } + } + } +@@ -341,8 +338,10 @@ WebAppBase* WebAppManager::OnLaunchUrl( + WebPageAdded(page); + + /* if the surface role is a background send ready to display them */ +- if (app_desc->SurfaceType() == AglShellSurfaceType::kBackground) ++ if (app_desc->SurfaceType() == AglShellSurfaceType::kBackground) { ++ LOG_DEBUG("Sending agl_ready from app %s", app_desc->Id().c_str()); + app->SendAglReady(); ++ } + + app_list_.push_back(app); + +@@ -831,8 +830,10 @@ void WebAppManager::UpdateNetworkStatus(const Json::Value& object) { + NetworkStatus status; + status.FromJsonObject(object); + ++#if defined(OS_WEBOS) + webos::Runtime::GetInstance()->SetNetworkConnected( + status.IsInternetConnectionAvailable()); ++#endif + network_status_manager_->UpdateNetworkStatus(status); + + if (status.IsInternetConnectionAvailable()) { +@@ -867,16 +868,12 @@ int WebAppManager::MaskForBrowsingDataType(const char* type) { + + void WebAppManager::AppInstalled(const std::string& app_id) { + LOG_INFO(MSGID_WAM_DEBUG, 0, "App installed; id=%s", app_id.c_str()); +- auto p = webos::ApplicationInstallationHandler::GetInstance(); +- if (p) +- p->OnAppInstalled(app_id); ++ ApplicationInstallationHandler::OnAppInstalled(app_id); + } + + void WebAppManager::AppRemoved(const std::string& app_id) { + LOG_INFO(MSGID_WAM_DEBUG, 0, "App removed; id=%s", app_id.c_str()); +- auto p = webos::ApplicationInstallationHandler::GetInstance(); +- if (p) +- p->OnAppRemoved(app_id); ++ ApplicationInstallationHandler::OnAppRemoved(app_id); + } + + std::string WebAppManager::IdentifierForSecurityOrigin( +@@ -889,5 +886,9 @@ std::string WebAppManager::IdentifierForSecurityOrigin( + LOG_WARNING(MSGID_APPID_HAS_UPPERCASE, 0, + "Application id should not contain capital letters"); + } ++#if defined(OS_WEBOS) + return (lowcase_identifier + webos::WebViewBase::kSecurityOriginPostfix); ++#else ++ return lowcase_identifier; ++#endif + } +diff --git a/src/core/web_app_manager.h b/src/core/web_app_manager.h +index b10f53d..0f30a85 100644 +--- a/src/core/web_app_manager.h ++++ b/src/core/web_app_manager.h +@@ -24,7 +24,7 @@ + #include <unordered_map> + #include <vector> + +-#include "webos/webview_base.h" ++#include "memory_pressure_level.h" + + class ApplicationDescription; + class DeviceInfo; +@@ -150,7 +150,7 @@ class WebAppManager { + const std::string& payload, + const std::string& app_id); + void UpdateNetworkStatus(const Json::Value& object); +- void NotifyMemoryPressure(webos::WebViewBase::MemoryPressureLevel level); ++ void NotifyMemoryPressure(MemoryPressureLevel level); + + bool IsEnyoApp(const std::string& app_id); + +diff --git a/src/core/web_app_manager_service.cc b/src/core/web_app_manager_service.cc +index 1770d02..90b880f 100644 +--- a/src/core/web_app_manager_service.cc ++++ b/src/core/web_app_manager_service.cc +@@ -19,6 +19,7 @@ + #include <json/value.h> + + #include "log_manager.h" ++#include "memory_pressure_level.h" + #include "web_app_base.h" + #include "web_app_manager_tracer.h" + +@@ -158,8 +159,7 @@ void WebAppManagerService::UpdateNetworkStatus(const Json::Value& object) { + WebAppManager::Instance()->UpdateNetworkStatus(object); + } + +-void WebAppManagerService::NotifyMemoryPressure( +- webos::WebViewBase::MemoryPressureLevel level) { ++void WebAppManagerService::NotifyMemoryPressure(MemoryPressureLevel level) { + WebAppManager::Instance()->NotifyMemoryPressure(level); + } + +diff --git a/src/core/web_app_manager_service.h b/src/core/web_app_manager_service.h +index 7ead117..c294e50 100644 +--- a/src/core/web_app_manager_service.h ++++ b/src/core/web_app_manager_service.h +@@ -22,7 +22,6 @@ + #include <vector> + + #include "web_app_manager.h" +-#include "webos/webview_base.h" + + namespace Json { + class Value; +@@ -114,7 +113,7 @@ class WebAppManagerService { + void KillCustomPluginProcess(const std::string& app_base_path); + void RequestKillWebProcess(uint32_t pid); + void UpdateNetworkStatus(const Json::Value& object); +- void NotifyMemoryPressure(webos::WebViewBase::MemoryPressureLevel level); ++ void NotifyMemoryPressure(MemoryPressureLevel level); + void SetAccessibilityEnabled(bool enable); + uint32_t GetWebProcessId(const std::string& app_id, + const std::string& instance_id); +diff --git a/src/core/web_page_base.h b/src/core/web_page_base.h +index 7bbca84..8a689a7 100644 +--- a/src/core/web_page_base.h ++++ b/src/core/web_page_base.h +@@ -20,8 +20,7 @@ + #include <memory> + #include <string> + +-#include "webos/webview_base.h" +- ++#include "memory_pressure_level.h" + #include "observer_list.h" + #include "util/url.h" + +@@ -58,8 +57,7 @@ class WebPageBase { + virtual void Init() = 0; + virtual void* GetWebContents() = 0; + virtual void SetLaunchParams(const std::string& params); +- virtual void NotifyMemoryPressure( +- webos::WebViewBase::MemoryPressureLevel level) {} ++ virtual void NotifyMemoryPressure(MemoryPressureLevel level) {} + + virtual std::string GetIdentifier() const; + virtual wam::Url Url() const = 0; +diff --git a/src/core/web_process_manager.h b/src/core/web_process_manager.h +index b63d270..c7ffde1 100644 +--- a/src/core/web_process_manager.h ++++ b/src/core/web_process_manager.h +@@ -17,6 +17,7 @@ + #ifndef CORE_WEB_PROCESS_MANAGER_H_ + #define CORE_WEB_PROCESS_MANAGER_H_ + ++#include <cstdint> + #include <list> + #include <string> + #include <unordered_map> +diff --git a/src/core/web_runtime.h b/src/core/web_runtime.h +index 69bc204..1ae6ca9 100644 +--- a/src/core/web_runtime.h ++++ b/src/core/web_runtime.h +@@ -21,8 +21,9 @@ + + class WebRuntime { + public: ++ virtual ~WebRuntime() = default; + static std::unique_ptr<WebRuntime> Create(); +- virtual int Run(int argc, const char** argv) = 0; ++ virtual int Run(int argc, char** argv) = 0; + }; + + #endif // CORE_WEB_RUNTIME_H_ +diff --git a/src/desktop/CMakeLists.txt b/src/desktop/CMakeLists.txt +new file mode 100644 +index 0000000..06078da +--- /dev/null ++++ b/src/desktop/CMakeLists.txt +@@ -0,0 +1,100 @@ ++project(WebAppMgrDesktop VERSION 1.0.0 DESCRIPTION "Web Application Manager library") ++ ++find_package(gRPC REQUIRED) ++find_program(GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin REQUIRED) ++find_package(Protobuf REQUIRED) ++find_package(Threads) ++ ++set(WAM_IPC_LIB_NAME ${PROJECT_NAME}IPC) ++set(WAM_IPC_PROTO_FILES ${WAM_ROOT_SOURCE_DIR}/cef/ipc/wam_ipc.proto) ++set(WAM_IPC_LIBS ++ protobuf::libprotobuf ++ gRPC::grpc ++ gRPC::grpc++ ++ gRPC::grpc++_reflection ++) ++set(WAM_IPC_INCLUDE_DIRS ++ ${CMAKE_CURRENT_BINARY_DIR} ++) ++ ++set(WAM_LIB_LIBS ++ ${JSONCPP_LDFLAGS} ++ WebAppMgrCore ++ ${WAM_IPC_LIB_NAME} ++ libcef_lib ++ libcef_dll_wrapper ++) ++ ++set(SOURCES ++ web_runtime_desktop.cc ++) ++ ++set(HEADERS ++ web_runtime_desktop.h ++) ++ ++set(WAM_LIB_CEF_DIR ${WAM_ROOT_SOURCE_DIR}/cef) ++ ++ ++set(WAM_LIB_INCLUDE_DIRS ++ ${JSONCPP_INCLUDE_DIRS} ++ ${CEF_INCLUDE_PATH} ++) ++ ++add_library(${WAM_IPC_LIB_NAME} SHARED ${WAM_IPC_PROTO_FILES}) ++target_include_directories(${WAM_IPC_LIB_NAME} PUBLIC ${WAM_IPC_INCLUDE_DIRS}) ++target_link_libraries(${WAM_IPC_LIB_NAME} PUBLIC ${WAM_IPC_LIBS}) ++set_target_properties(${WAM_IPC_LIB_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1.0) ++protobuf_generate(TARGET ${WAM_IPC_LIB_NAME} LANGUAGE cpp APPEND_PATH) ++protobuf_generate(TARGET ${WAM_IPC_LIB_NAME} LANGUAGE grpc APPEND_PATH GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${GRPC_CPP_PLUGIN_EXECUTABLE}") ++install(TARGETS ${WAM_IPC_LIB_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++ ++ ++LIST(APPEND SOURCES ++ ${WAM_LIB_CEF_DIR}/device_info_cef.cc ++ ${WAM_LIB_CEF_DIR}/platform_module_factory_cef.cc ++ ${WAM_LIB_CEF_DIR}/ipc/web_app_manager_service_grpc.cc ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_browser_handler.cc ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_client.cc ++) ++LIST(APPEND HEADERS ++ ${WAM_LIB_CEF_DIR}/device_info_cef.h ++ ${WAM_LIB_CEF_DIR}/platform_module_factory_cef.h ++ ${WAM_LIB_CEF_DIR}/ipc/web_app_manager_service_grpc.h ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_browser_handler.h ++ ${WAM_LIB_CEF_DIR}/handlers/wam_cef_client.h ++) ++LIST(APPEND WAM_LIB_INCLUDE_DIRS ++ ${WAM_LIB_CEF_DIR} ++ ${WAM_LIB_CEF_DIR}/ipc ++ ${WAM_LIB_CEF_DIR}/webapp ++) ++ ++add_library(${PROJECT_NAME} SHARED ${HEADERS} ${SOURCES}) ++target_include_directories(${PROJECT_NAME} PUBLIC ${WAM_LIB_INCLUDE_DIRS}) ++set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1.0) ++ ++install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/webappmanager) ++ ++macro(INSTALL_CEF_FILES file_list source_dir target_dir) ++ foreach(FILENAME ${file_list}) ++ set(source_file ${source_dir}/${FILENAME}) ++ ++ # Remove the target file path component. ++ get_filename_component(target_name ${FILENAME} NAME) ++ set(target_file ${target_dir}/${target_name}) ++ ++ if (IS_DIRECTORY ${source_file}) ++ install(DIRECTORY ${source_file} DESTINATION ${target_dir}) ++ else() ++ install(FILES ${source_file} DESTINATION ${target_dir}) ++ endif() ++ endforeach() ++endmacro() ++ ++# Copy CEF dependencies ++install_cef_files("${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CMAKE_INSTALL_PREFIX}") ++install_cef_files("${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CMAKE_INSTALL_PREFIX}") ++ ++target_link_libraries(${PROJECT_NAME} PUBLIC ${WAM_LIB_LIBS}) ++install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) +diff --git a/src/desktop/README.md b/src/desktop/README.md +new file mode 100644 +index 0000000..2d32b39 +--- /dev/null ++++ b/src/desktop/README.md +@@ -0,0 +1,102 @@ ++# CEF backend ++ ++This is an experimental CEF backend for WAM. ++ ++## Compilation ++ ++### Preparations ++ ++First prepare a workspace: ++``` ++mkdir wam-cef ++cd wam-cef ++``` ++ ++Now clone WAM repository: ++``` ++git clone ssh://git@gitlab.igalia.com:4429/dape/wam.git ++``` ++ ++Fetch latest stable CEF binary distribution (standard) for your system, from [CEF binary download](https://cef-builds.spotifycdn.com/index.html). Then uncompress the tarball: ++``` ++tar xvf ...path...to...binary/cef_binary...tar.bz2 ++``` ++ ++### Compilation of CEF DLL wrapper ++ ++Create a folder to compile the CEF DLL wrapper `.a` file: ++``` ++mkdir build-cef-dll ++cd build-cef-dll ++``` ++ ++Prepare compilation scripts: ++``` ++cmake ../cef_binary_... ++``` ++ ++Then compile the DLL wrapper: ++``` ++make libcef_dll_wrapper ++``` ++ ++Finally go back to the top directory: ++``` ++cd .. ++``` ++ ++After this, you can see the wrapper at `build-cef-dll/libcef_dll_wrapper/libcef_dll_wrapper.a`. ++ ++### Test applications ++ ++You can just use webOS `test-apps` repository: ++``` ++git clone https://github.com/webosose/test-apps.git ++``` ++ ++### Compilation of WAM ++ ++Prepare build folder: ++ ++``` ++mkdir build-wam ++cd build-wam ++mkdir wam-install ++``` ++ ++Then call *CMake* to generate the compilation scripts. You will need to pass several variables: ++* `CEF_ROOT`: full path to the CEF dist directory. ++* `CMAKE_INSTALL_PREFIX`: base install directory. ++* `CMAKE_INSTALL_BINDIR`: where executables will go. ++* `CMAKE_INSTALL_LIBDIR`: libraries. ++* `CMAKE_INSTALL_INCLUDEDIR`: path for includes. ++ ++You can also use `CMAKE_BUILD_TYPE` to set `Debug` or `Release` builds. ++ ++An example of the *CMake* invokation: ++``` ++cmake -DCMAKE_INSTALL_PREFIX=$PWD/wam-install -DCMAKE_INSTALL_BINDIR=$PWD/wam-install/bin -DCMAKE_INSTALL_LIBDIR=$PWD/wam-install/lib -DCMAKE_INSTALL_INCLUDEDIR=$PWD/wam-install/include -DCEF_ROOT=$WAM_BASE_PATH/cef_binary_114.2.10+g398e3c3+chromium-114.0.5735.110_linux64/Debug/ -DCMAKE_BUILD_TYPE=Debug ++``` ++ ++And finally compilation of WAM: ++``` ++make ++``` ++ ++And installation: ++``` ++make install ++``` ++ ++## Running ++ ++To run the daemon, you can do: ++``` ++cd wam-install/bin ++WEBAPPFACTORY_PLUGIN_PATH=../lib/webappmanager/plugins/ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib:$WAM_BASE_PATH/cef_binary_114.2.10+g398e3c3+chromium-114.0.5735.110_linux64/Release/ ./WebAppMgr & ++``` ++ ++Then, you can launch an application: ++``` ++LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ../WebAppMgrDesktopCli --app-id=bareapp --app-install-dir=$WAM_BASE_PATH/test-apps/bareapp/ ++``` +diff --git a/src/desktop/web_runtime_desktop.cc b/src/desktop/web_runtime_desktop.cc +new file mode 100644 +index 0000000..49d1914 +--- /dev/null ++++ b/src/desktop/web_runtime_desktop.cc +@@ -0,0 +1,28 @@ ++#include "web_runtime_desktop.h" ++ ++#include "include/cef_base.h" ++ ++#include "wam_cef_browser_handler.h" ++ ++int WebRuntimeDesktop::Run(int argc, char** argv) { ++ CefMainArgs main_args(argc, argv); ++ ++ CefRefPtr<CefApp> app = new WamCefBrowserHandler; ++ auto exit_code = CefExecuteProcess(main_args, app.get(), nullptr); ++ if (exit_code >= 0) { ++ return exit_code; ++ } ++ ++ CefSettings settings; ++ CefInitialize(main_args, settings, app.get(), nullptr); ++ ++ CefRunMessageLoop(); ++ ++ CefShutdown(); ++ ++ return 0; ++} ++ ++std::unique_ptr<WebRuntime> WebRuntime::Create() { ++ return std::make_unique<WebRuntimeDesktop>(); ++} +diff --git a/src/desktop/web_runtime_desktop.h b/src/desktop/web_runtime_desktop.h +new file mode 100644 +index 0000000..e65f738 +--- /dev/null ++++ b/src/desktop/web_runtime_desktop.h +@@ -0,0 +1,11 @@ ++#ifndef DESKTOP_WEB_RUNTIME_CEF_H_ ++#define DESKTOP_WEB_RUNTIME_CEF_H_ ++ ++#include "web_runtime.h" ++ ++class WebRuntimeDesktop : public WebRuntime { ++ public: ++ int Run(int argc, char** argv) override; ++}; ++ ++#endif // DESKTOP_WEB_RUNTIME_CEF_H_ +diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt +index 876921b..b401dca 100644 +--- a/src/platform/CMakeLists.txt ++++ b/src/platform/CMakeLists.txt +@@ -17,10 +17,6 @@ + project(WebAppMgr VERSION 1.0.0 DESCRIPTION "Web Application Manager library") + + set(SOURCES +- palm_system_webos.cc +- web_app_wayland.cc +- web_app_wayland_window.cc +- web_app_window_impl.cc + webengine/blink_web_process_manager.cc + webengine/blink_web_view.cc + webengine/blink_web_view_profile_helper.cc +@@ -32,12 +28,8 @@ set(SOURCES + ) + + set(HEADERS +- palm_system_webos.h +- web_app_wayland.h +- web_app_wayland_window.h + web_app_window.h + web_app_window_factory.h +- web_app_window_impl.h + webengine/blink_web_process_manager.h + webengine/blink_web_view.h + webengine/blink_web_view_profile_helper.h +@@ -67,6 +59,21 @@ set(WAM_LIB_LIBS + WebAppMgrCore + ) + ++if (WEBENGINE_CBE) ++ LIST(APPEND SOURCES ++ web_app_window_impl.h ++ web_app_wayland_window.cc ++ palm_system_webos.cc ++ web_app_wayland.cc ++ ) ++ LIST(APPEND HEADERS ++ palm_system_webos.h ++ web_app_wayland.h ++ web_app_wayland_window.h ++ web_app_window_impl.h ++ ) ++endif() ++ + if (OS_WEBOS) + LIST(APPEND SOURCES + ${WAM_ROOT_SOURCE_DIR}/webos/palm_service_base.cc +diff --git a/src/platform/web_app_window.h b/src/platform/web_app_window.h +index 7381b0c..a90127f 100644 +--- a/src/platform/web_app_window.h ++++ b/src/platform/web_app_window.h +@@ -20,8 +20,6 @@ + #include <string> + #include <vector> + +-#include "webos/webapp_window_base.h" +- + class WebAppWayland; + + class WebAppWindow { +@@ -32,12 +30,14 @@ class WebAppWindow { + virtual int DisplayWidth() = 0; + virtual int DisplayHeight() = 0; + virtual void InitWindow(int width, int height) = 0; +- virtual void SetLocationHint(webos::WebAppWindowBase::LocationHint value) = 0; ++ virtual void SetLocationHint(const std::string& value) = 0; + virtual webos::NativeWindowState GetWindowHostState() const = 0; ++#if defined(OS_WEBOS) + virtual void CreateWindowGroup( + const webos::WindowGroupConfiguration& config) = 0; + virtual void AttachToWindowGroup(const std::string& name, + const std::string& layer) = 0; ++#endif + virtual bool IsKeyboardVisible() = 0; + virtual void SetKeyMask(webos::WebOSKeyMask key_mask) = 0; + virtual void SetKeyMask(webos::WebOSKeyMask key_mask, bool set) = 0; +diff --git a/src/util/log_msg_id.h b/src/util/log_msg_id.h +index 7d114cf..71d9621 100644 +--- a/src/util/log_msg_id.h ++++ b/src/util/log_msg_id.h +@@ -150,6 +150,8 @@ + + #define MSGID_DL_ERROR "DL_ERROR" /** Dinamic load library error **/ + ++#define MSGID_ERROR_CANNOT_LOCK_SERVICE "MSGID_CANNOT_LOCK_SERVICE" /** Cannot lock the GRPC IPC lock **/ ++ + // clang-format on + + #endif // LOGMSGID_H +diff --git a/src/util/timer.h b/src/util/timer.h +index 795a38c..6824fb8 100644 +--- a/src/util/timer.h ++++ b/src/util/timer.h +@@ -30,12 +30,12 @@ class Timer { + : source_id_(0), is_running_(false), is_repeating_(is_repeating) {} + virtual ~Timer() {} + +- // Timer + virtual void HandleCallback() = 0; +- virtual void Start(int delay_in_milli_seconds); + + bool IsRunning() { return is_running_; } + bool IsRepeating() { return is_repeating_; } ++ ++ void Start(int delay_in_milli_seconds); + void Stop(); + + protected: +diff --git a/src/wam_main.cc b/src/wam_main.cc +index 0c04a40..d559ee4 100644 +--- a/src/wam_main.cc ++++ b/src/wam_main.cc +@@ -14,11 +14,9 @@ + // + // SPDX-License-Identifier: Apache-2.0 + +-#include <webos/app/webos_main.h> +- + #include "web_runtime.h" + +-int main(int argc, const char** argv) { ++int main(int argc, char** argv) { + std::unique_ptr<WebRuntime> web_runtime(WebRuntime::Create()); + return web_runtime->Run(argc, argv); + } +diff --git a/src/webos/web_app_manager_service_luna.cc b/src/webos/web_app_manager_service_luna.cc +index 627cf31..b69635f 100644 +--- a/src/webos/web_app_manager_service_luna.cc ++++ b/src/webos/web_app_manager_service_luna.cc +@@ -632,6 +632,7 @@ void WebAppManagerServiceLuna::GetForegroundAppInfoCallback( + if (cleared_cache_) + cleared_cache_ = false; + ++#if defined(OS_WEBOS) + if (reply["returnValue"] == true) { + if (reply.isMember("appId") && reply["appId"].isString()) { + std::string appId = reply["appId"].asString(); +@@ -639,6 +640,7 @@ void WebAppManagerServiceLuna::GetForegroundAppInfoCallback( + WebAppManagerService::IsEnyoApp(appId.c_str())); + } + } ++#endif + } + + void WebAppManagerServiceLuna::BootdConnectCallback(const Json::Value& reply) { +diff --git a/src/webos/web_runtime_webos.cc b/src/webos/web_runtime_webos.cc +index 9dd2f72..cab7e5a 100644 +--- a/src/webos/web_runtime_webos.cc ++++ b/src/webos/web_runtime_webos.cc +@@ -70,7 +70,7 @@ class WebOSMainDelegateWAM : public webos::WebOSMainDelegate { + void AboutToCreateContentBrowserClient() override { StartWebAppManager(); } + }; + +-int WebRuntimeWebOS::Run(int argc, const char** argv) { ++int WebRuntimeWebOS::Run(int argc, char** argv) { + WebOSMainDelegateWAM delegate; + webos::WebOSMain webos_main(&delegate); + return webOSMain.Run(argc, argv); +diff --git a/src/webos/web_runtime_webos.h b/src/webos/web_runtime_webos.h +index eb52348..fa031a2 100644 +--- a/src/webos/web_runtime_webos.h ++++ b/src/webos/web_runtime_webos.h +@@ -21,7 +21,7 @@ + + class WebRuntimeWebOS : public WebRuntime { + public: +- int Run(int argc, const char** argv) override; ++ int Run(int argc, char** argv) override; + }; + + #endif // WEBOS_WEB_RUNTIME_WEBOS_H_ +-- +2.39.2 + |