1 // Copyright 2019 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ewk_interface_main.h"
7 #include "build/build_config.h"
9 #define TIZEN_VERSION \
10 (TIZEN_VERSION_MAJOR * 10000 + TIZEN_VERSION_MINOR * 100 + \
12 #define TIZEN_VERSION_AT_LEAST(major, minor, patch) \
13 (TIZEN_VERSION >= (major * 10000 + minor * 100 + patch))
15 #define CHROMIUM_PRELOAD_LIB_PATH LIB_RO_ROOT_DIR "/lib/" CHROMIUM_IMPL_LIB_FILE
17 #if BUILDFLAG(IS_TIZEN_TV)
18 #define PATH_PRELOAD_CHROMIUM_EFL_IMG APP_RO_ROOT_DIR "/res/chromium-efl.img"
19 #define MOUNT_ARGS_PRELOAD_CHROMIUM \
20 PATH_PRELOAD_CHROMIUM_EFL_IMG " " LIB_RO_ROOT_DIR " -t squashfs -o loop,ro"
22 #define CHROMIUM_UPGRADE_LIB_PATH \
23 LIB_UPGRADE_ROOT_DIR "/lib/" CHROMIUM_IMPL_LIB_FILE
28 #include <sys/resource.h>
29 #endif // BUILDFLAG(IS_TIZEN_TV)
32 #include <EWebKit_internal.h>
33 #include <EWebKit_product.h>
38 #include "dlog_util.h"
43 #if defined(ENABLE_WRT_JS)
44 #if BUILDFLAG(IS_TIZEN_TV)
45 #include <linux/loop.h>
46 #include <sys/ioctl.h>
47 #include <sys/mount.h>
48 #include <sys/resource.h>
49 #include <sys/statfs.h>
50 #include <vconf/vconf.h>
52 #if TIZEN_VERSION_AT_LEAST(8, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
53 #include <launchpad/launchpad.h>
55 #endif // BUILDFLAG(IS_TIZEN_TV)
58 namespace ewk_interface {
60 void* g_impl_lib_handle = nullptr;
61 int dlopen_mode = RTLD_LAZY | RTLD_GLOBAL;
63 inline unsigned long long ConvertMilliseconds(timespec ts) {
64 return ((unsigned long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
67 #if BUILDFLAG(IS_TIZEN_TV)
68 bool g_upgrade_lib = false; // conservative policy
69 const char* kChromiumMountReady = "/tmp/.chromium_mount.ready";
70 #endif // BUILDFLAG(IS_TIZEN_TV)
72 #if defined(ENABLE_WRT_JS)
73 #if BUILDFLAG(IS_TIZEN_TV)
74 #define SQUASHFS_MAGIC 0x73717368
76 const char* kUWETag = "USE_UWE";
77 const char* kWrtLoaderCompleted = "/tmp/.wrt_loader.completed";
79 #if TIZEN_VERSION_AT_LEAST(8, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
80 const int kBooTypeLastModeUrlLauncher = 2;
81 const char* kEPAppbootType = "db/ep-common/last_mode";
84 char app_define_base_path[128] = {0};
85 bool direct_mounted = false;
87 bool IsFirstWrtLoader() {
88 return direct_mounted || access(kWrtLoaderCompleted, F_OK) != 0;
91 void DisposeLoaderIfNecessary() {
92 #if TIZEN_VERSION_AT_LEAST(8, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
93 LOG(INFO) << "DisposeLoaderIfNecessary for LFD";
94 if (!IsFirstWrtLoader()) {
95 // skip if this is not first wrt-loader
99 LOG(INFO) << "wrt-loader first launched!!";
102 if (vconf_get_int(kEPAppbootType, &boot_type) != 0) {
103 LOG(ERROR) << "vconf error : " << kEPAppbootType;
107 LOG(INFO) << "boot type == " << boot_type;
108 if (boot_type != kBooTypeLastModeUrlLauncher) {
109 LOG(INFO) << "wrt-loader not needed!";
110 launchpad_loader_dispose();
112 #endif // TIZEN_VERSION_AT_LEAST(8, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
115 void SetPriority(int absolute) {
116 setpriority(PRIO_PROCESS, 0, absolute);
117 LOG(INFO) << "Set process priority : " << absolute;
120 void LowerPriorityIfNecessary() {
122 clock_gettime(CLOCK_MONOTONIC, &now);
123 auto current_time = ConvertMilliseconds(now);
124 if (current_time > 120000 || IsFirstWrtLoader()) {
125 // skip if kerneltime is over 120 or if this is first wrt-loader
129 char* foreground_app = vconf_get_str("memory/wrt/most_recent_foreground");
130 if (!foreground_app || strlen(foreground_app) < 10) {
131 LOG(INFO) << "There is no FG webapp";
132 if (foreground_app) free(foreground_app);
135 LOG(INFO) << "most_recent_foreground : " << foreground_app
136 << ", current_time : " << current_time;
137 free(foreground_app);
141 bool DirectMount(const char* image_path, const char* point_point) {
142 const char* dev_loop_control = "/dev/loop-control";
143 const char* dev_loop_prefix = "/dev/loop";
146 struct statfs _statfs;
147 ret = statfs(point_point, &_statfs);
149 LOG(ERROR) << "Error getting statfs";
152 if (_statfs.f_type == SQUASHFS_MAGIC) {
153 LOG(INFO) << "Already mounted";
157 const auto loop_control = std::fopen(dev_loop_control, "r");
159 LOG(ERROR) << "Cannot open : " << dev_loop_control;
163 LOG(INFO) << "Direct mount start";
164 const auto loop_control_fd = fileno(loop_control);
165 const auto devnr = ioctl(loop_control_fd, LOOP_CTL_GET_FREE);
166 std::stringstream loopname;
167 loopname << dev_loop_prefix << devnr;
168 const auto loop_device_name = loopname.str();
169 const auto loop_device = std::fopen(loop_device_name.c_str(), "r");
171 LOG(ERROR) << "Cannot open : " << loop_device_name;
172 std::fclose(loop_control);
175 const auto loop_device_fd = fileno(loop_device);
176 const auto image = std::fopen(image_path, "r");
178 LOG(ERROR) << "Cannot open : " << image_path;
179 std::fclose(loop_device);
180 std::fclose(loop_control);
184 const auto image_fd = fileno(image);
185 ioctl(loop_device_fd, LOOP_SET_FD, image_fd);
186 const auto result = mount(loop_device_name.c_str(), point_point, "squashfs",
188 ioctl(loop_device_fd, LOOP_CLR_FD, 0);
190 std::fclose(loop_device);
191 std::fclose(loop_control);
192 LOG(INFO) << "Direct mount end";
196 bool MountDefaultChromiumImage() {
197 if (access(CHROMIUM_PRELOAD_LIB_PATH, F_OK) == 0) {
198 LOG(INFO) << "Already libchromium-impl.so exists";
202 if (!DirectMount(PATH_PRELOAD_CHROMIUM_EFL_IMG, LIB_RO_ROOT_DIR)) {
203 LOG(ERROR) << "Direct mount has failed, will wait efl-install-service";
206 direct_mounted = true;
210 void SetIndependentUWEPath(const char* base_path) {
211 // base_path: /opt/usr/apps/{pkgid}/bin/{appid}
212 // get pkgid by parsing base_path, concatenate $app_define_base_path
213 const static size_t prefix_len = strlen("/opt/usr/apps/");
214 auto p = strchr(base_path + prefix_len, '/');
215 char pkgid[64] = {0};
216 strncpy(pkgid, base_path + prefix_len, p - base_path - prefix_len);
217 snprintf(app_define_base_path, sizeof(app_define_base_path),
218 "/home/owner/apps_rw/%s/shared/res/", pkgid);
221 void TryOpenAppDefinedLib() {
222 if (g_impl_lib_handle)
224 if (strlen(app_define_base_path) == 0)
226 if (access(app_define_base_path, F_OK) != 0)
229 char app_defined_lib[256] = {0};
230 snprintf(app_defined_lib, sizeof(app_defined_lib),
231 "%s/lib/libchromium-impl.so", app_define_base_path);
232 LOG(INFO) << "app_defined_lib : " << app_defined_lib;
234 if (access(app_defined_lib, F_OK) != 0)
236 g_impl_lib_handle = dlopen(app_defined_lib, RTLD_LAZY | RTLD_GLOBAL);
237 if (!g_impl_lib_handle) {
238 LOG(ERROR) << "dlopen error : " << dlerror();
242 #endif // BUILDFLAG(IS_TIZEN_TV)
245 void* open_library() {
246 if (g_impl_lib_handle)
247 return g_impl_lib_handle;
249 #if BUILDFLAG(IS_TIZEN_TV)
250 g_upgrade_lib = (g_upgrade_lib && !access(CHROMIUM_UPGRADE_LIB_PATH, F_OK));
252 g_upgrade_lib ? CHROMIUM_UPGRADE_LIB_PATH : CHROMIUM_PRELOAD_LIB_PATH;
254 const char* path = CHROMIUM_PRELOAD_LIB_PATH;
257 #if defined(USE_TTRACE)
258 traceBegin(TTRACE_TAG_WEB, "dlopen start");
261 unsigned long long diff;
262 struct timespec begin, end;
263 struct stat file_stat;
265 stat(path, &file_stat);
266 clock_gettime(CLOCK_MONOTONIC, &begin);
267 g_impl_lib_handle = dlopen(path, dlopen_mode);
268 clock_gettime(CLOCK_MONOTONIC, &end);
269 if (!g_impl_lib_handle)
270 LOG(ERROR) << "dlopen error : " << dlerror();
271 diff = ConvertMilliseconds(end) - ConvertMilliseconds(begin);
272 LOG(ERROR) << "Open library done. cost:" << diff << "ms\npath:" << path
273 << " size:" << file_stat.st_size / (1024 * 1024) << "MB";
275 #if defined(USE_TTRACE)
276 traceEnd(TTRACE_TAG_WEB);
278 // FIXME:Need to call dlclose(), to make sure that the opened chromium-impl
279 // library joins all threads forked by chromium
280 return g_impl_lib_handle;
283 } // namespace ewk_interface
285 using namespace ewk_interface;
287 static void _ewk_force_acceleration() __attribute__((constructor));
289 void _ewk_force_acceleration() {
290 // Chromium-efl port does not support s/w mode. So we need to set h/w mode
291 // before creating elm_window. To do this, make constructor function which is
292 // called at library loading time and set "ELM_ACCEL=hw" here. If not, native
293 // app which does not call elm_config_accel_preference_set() function will
295 setenv("ELM_ACCEL", "hw", 1);
297 // Chromium-efl does not support evasgl render thread feature yet.
298 setenv("EVAS_GL_DISABLE_RENDER_THREAD", "1", 1);
301 void* ewk_dlsym(const char* function_name) {
302 #if defined(ENABLE_WRT_JS) && BUILDFLAG(IS_TIZEN_TV)
303 TryOpenAppDefinedLib();
306 if (!g_impl_lib_handle && !open_library())
309 void* function_addr = dlsym(g_impl_lib_handle, function_name);
311 LOG(ERROR) << "No " << function_name << " symbol found! " << dlerror();
313 return function_addr;
316 Eina_Bool ewk_wait_chromium_ready(unsigned int timeout_msec) {
317 #if BUILDFLAG(IS_TIZEN_TV)
318 LOG(INFO) << "ewk_wait_chromium_ready called. timeout : " << timeout_msec;
320 int ret = LwipcWaitEvent(kChromiumMountReady, timeout_msec);
322 LOG(INFO) << "chromium mount is done.";
325 LOG(ERROR) << "chromium mount is not ready yet: "
326 << (ret > 0 ? "timeout" : "fail");
328 LOG(WARN) << "Not supported function";
333 Eina_Bool ewk_check_chromium_ready() {
334 #if BUILDFLAG(IS_TIZEN_TV)
335 LOG(INFO) << "ewk_check_chromium_ready called.";
337 if (LwipcIsDone(kChromiumMountReady) > 0) {
338 LOG(INFO) << "chromium mount is done.";
341 LOG(ERROR) << "chromium mount is not ready yet.";
343 LOG(WARN) << "Not supported function";
348 int ewk_set_version_policy(int preference) {
349 #if BUILDFLAG(IS_TIZEN_TV)
350 int ret = preference;
352 g_upgrade_lib = false; // conservative
353 else if (1 == preference)
354 g_upgrade_lib = true; // progressive
356 // todo : we can add the exact version policy like 63, 69 in the future.
357 ret = g_upgrade_lib ? 1 : 0;
358 LOG(ERROR) << "Unknown preference:" << preference << " current:" << ret;
360 LOG(INFO) << "ewk_set_version_policy : " << ret;
361 typedef int (*func_ptr_t)(int);
363 reinterpret_cast<func_ptr_t>(ewk_dlsym("ewk_set_version_policy"));
365 return fp(preference);
366 } else if (g_upgrade_lib) {
368 LOG(ERROR) << "ewk_set_version_policy is not found. UWE request is ignored";
369 g_upgrade_lib = false;
374 LOG(WARN) << "Not supported function";
380 LOG(INFO) << "EWK-INTERFACE : ewk_init called..";
381 typedef int (*func_ptr_t)(void);
382 func_ptr_t fp = reinterpret_cast<func_ptr_t>(ewk_dlsym("ewk_init"));
388 int ewk_shutdown(void) {
389 LOG(INFO) << "EWK-INTERFACE : ewk_shutdown called..";
390 typedef int (*func_ptr_t)(void);
391 func_ptr_t fp = reinterpret_cast<func_ptr_t>(ewk_dlsym("ewk_shutdown"));
401 __attribute__((visibility("default"))) int efl_webprocess_main(
404 LOG(INFO) << "EWK-INTERFACE : efl_webprocess_main called..";
406 #if BUILDFLAG(IS_TIZEN_TV)
407 if (!g_impl_lib_handle && !access(CHROMIUM_UPGRADE_LIB_PATH, F_OK)) {
408 // If library is not loaded and upgrade package is installed,
409 // we need to decide upgrade library by command line flag --impl-library
410 // appended in browser process.
411 for (int i = 1; i < argc; ++i) {
412 if (!strcmp(argv[i], "--impl-library-upgrade")) {
413 g_upgrade_lib = true;
417 LOG(INFO) << "Version policy : " << g_upgrade_lib;
421 typedef int (*func_ptr_t)(int argc, const char** argv);
423 reinterpret_cast<func_ptr_t>(ewk_dlsym("efl_webprocess_main"));
425 return fp(argc, argv);
429 #if defined(ENABLE_WRT_JS)
430 __attribute__((visibility("default")))
431 int WRTMain(int argc, char** argv) {
432 LOG(INFO) << "EWK-INTERFACE : WRTMain called..";
433 #if BUILDFLAG(IS_TIZEN_TV)
434 if (strcmp(argv[0], "/usr/bin/wrt-loader") == 0) {
435 DisposeLoaderIfNecessary();
436 LowerPriorityIfNecessary();
438 if (!MountDefaultChromiumImage() && !ewk_wait_chromium_ready(20000)) {
442 if (IsFirstWrtLoader())
443 dlopen_mode = RTLD_NOW | RTLD_GLOBAL;
445 for (int i = 1; i < argc; ++i) {
446 if (strncmp(argv[i], kUWETag, strlen(kUWETag)) == 0) {
447 LOG(INFO) << "USE UWE";
448 SetIndependentUWEPath(argv[0]);
449 ewk_set_version_policy(1); // use latest engine
455 typedef int (*func_ptr_t)(int argc, char** argv);
456 func_ptr_t fp = reinterpret_cast<func_ptr_t>(ewk_dlsym("WRTMain"));
458 return fp(argc, argv);
462 __attribute__((visibility("default")))
463 int WRTServiceMain(int argc, char** argv) {
464 LOG(INFO) << "EWK-INTERFACE : WRTServiceMain called..";
465 typedef int (*func_ptr_t)(int argc, char** argv);
466 func_ptr_t fp = reinterpret_cast<func_ptr_t>(ewk_dlsym("WRTServiceMain"));
468 return fp(argc, argv);