[M120 Migration][MM] Handle live stream duration and currenttime
[platform/framework/web/chromium-efl.git] / tizen_src / downloadable / ewk_interface_main.cc
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.
4
5 #include "ewk_interface_main.h"
6
7 #include "build/build_config.h"
8
9 #define TIZEN_VERSION                                        \
10   (TIZEN_VERSION_MAJOR * 10000 + TIZEN_VERSION_MINOR * 100 + \
11    TIZEN_VERSION_PATCH)
12 #define TIZEN_VERSION_AT_LEAST(major, minor, patch) \
13   (TIZEN_VERSION >= (major * 10000 + minor * 100 + patch))
14
15 #define CHROMIUM_PRELOAD_LIB_PATH LIB_RO_ROOT_DIR "/lib/" CHROMIUM_IMPL_LIB_FILE
16
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"
21
22 #define CHROMIUM_UPGRADE_LIB_PATH \
23   LIB_UPGRADE_ROOT_DIR "/lib/" CHROMIUM_IMPL_LIB_FILE
24
25 #include <lwipc.h>
26 #include <ttrace.h>
27
28 #include <sys/resource.h>
29 #endif  // BUILDFLAG(IS_TIZEN_TV)
30
31 #include <EWebKit.h>
32 #include <EWebKit_internal.h>
33 #include <EWebKit_product.h>
34
35 #include <dlfcn.h>
36 #include <unistd.h>
37
38 #include "dlog_util.h"
39
40 #include <sys/stat.h>
41 #include <sys/time.h>
42
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>
51
52 #if TIZEN_VERSION_AT_LEAST(8, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
53 #include <launchpad/launchpad.h>
54 #endif
55 #endif  // BUILDFLAG(IS_TIZEN_TV)
56 #endif
57
58 namespace ewk_interface {
59
60 void* g_impl_lib_handle = nullptr;
61 int dlopen_mode = RTLD_LAZY | RTLD_GLOBAL;
62
63 inline unsigned long long ConvertMilliseconds(timespec ts) {
64   return ((unsigned long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
65 }
66
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)
71
72 #if defined(ENABLE_WRT_JS)
73 #if BUILDFLAG(IS_TIZEN_TV)
74 #define SQUASHFS_MAGIC 0x73717368
75
76 const char* kUWETag = "USE_UWE";
77 const char* kWrtLoaderCompleted = "/tmp/.wrt_loader.completed";
78
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";
82 #endif
83
84 char app_define_base_path[128] = {0};
85 bool direct_mounted = false;
86
87 bool IsFirstWrtLoader() {
88   return direct_mounted || access(kWrtLoaderCompleted, F_OK) != 0;
89 }
90
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
96     return;
97   }
98
99   LOG(INFO) << "wrt-loader first launched!!";
100
101   int boot_type = 0;
102   if (vconf_get_int(kEPAppbootType, &boot_type) != 0) {
103     LOG(ERROR) << "vconf error : " << kEPAppbootType;
104     return;
105   }
106
107   LOG(INFO) << "boot type == " << boot_type;
108   if (boot_type != kBooTypeLastModeUrlLauncher) {
109     LOG(INFO) << "wrt-loader not needed!";
110     launchpad_loader_dispose();
111   }
112 #endif  // TIZEN_VERSION_AT_LEAST(8, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
113 }
114
115 void SetPriority(int absolute) {
116   setpriority(PRIO_PROCESS, 0, absolute);
117   LOG(INFO) << "Set process priority : " << absolute;
118 }
119
120 void LowerPriorityIfNecessary() {
121   struct timespec now;
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
126     return;
127   }
128
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);
133     return;
134   }
135   LOG(INFO) << "most_recent_foreground : " << foreground_app
136             << ", current_time : " << current_time;
137   free(foreground_app);
138   SetPriority(10);
139 }
140
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";
144
145   int ret;
146   struct statfs _statfs;
147   ret = statfs(point_point, &_statfs);
148   if (ret < 0) {
149     LOG(ERROR) << "Error getting statfs";
150     return false;
151   }
152   if (_statfs.f_type == SQUASHFS_MAGIC) {
153     LOG(INFO) << "Already mounted";
154     return true;
155   }
156
157   const auto loop_control = std::fopen(dev_loop_control, "r");
158   if (!loop_control) {
159     LOG(ERROR) << "Cannot open : " << dev_loop_control;
160     return false;
161   }
162
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");
170   if (!loop_device) {
171     LOG(ERROR) << "Cannot open : " << loop_device_name;
172     std::fclose(loop_control);
173     return false;
174   }
175   const auto loop_device_fd = fileno(loop_device);
176   const auto image = std::fopen(image_path, "r");
177   if (!image) {
178     LOG(ERROR) << "Cannot open : " << image_path;
179     std::fclose(loop_device);
180     std::fclose(loop_control);
181     return false;
182   }
183
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",
187                             MS_RDONLY, nullptr);
188   ioctl(loop_device_fd, LOOP_CLR_FD, 0);
189   std::fclose(image);
190   std::fclose(loop_device);
191   std::fclose(loop_control);
192   LOG(INFO) << "Direct mount end";
193   return result == 0;
194 }
195
196 bool MountDefaultChromiumImage() {
197   if (access(CHROMIUM_PRELOAD_LIB_PATH, F_OK) == 0) {
198     LOG(INFO) << "Already libchromium-impl.so exists";
199     return true;
200   }
201
202   if (!DirectMount(PATH_PRELOAD_CHROMIUM_EFL_IMG, LIB_RO_ROOT_DIR)) {
203     LOG(ERROR) << "Direct mount has failed, will wait efl-install-service";
204     return false;
205   }
206   direct_mounted = true;
207   return true;
208 }
209
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);
219 }
220
221 void TryOpenAppDefinedLib() {
222   if (g_impl_lib_handle)
223     return;
224   if (strlen(app_define_base_path) == 0)
225     return;
226   if (access(app_define_base_path, F_OK) != 0)
227     return;
228
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;
233
234   if (access(app_defined_lib, F_OK) != 0)
235     return;
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();
239     return;
240   }
241 }
242 #endif  // BUILDFLAG(IS_TIZEN_TV)
243 #endif
244
245 void* open_library() {
246   if (g_impl_lib_handle)
247     return g_impl_lib_handle;
248
249 #if BUILDFLAG(IS_TIZEN_TV)
250   g_upgrade_lib = (g_upgrade_lib && !access(CHROMIUM_UPGRADE_LIB_PATH, F_OK));
251   const char* path =
252       g_upgrade_lib ? CHROMIUM_UPGRADE_LIB_PATH : CHROMIUM_PRELOAD_LIB_PATH;
253 #else
254   const char* path = CHROMIUM_PRELOAD_LIB_PATH;
255 #endif
256
257 #if defined(USE_TTRACE)
258   traceBegin(TTRACE_TAG_WEB, "dlopen start");
259 #endif
260
261   unsigned long long diff;
262   struct timespec begin, end;
263   struct stat file_stat;
264
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";
274
275 #if defined(USE_TTRACE)
276   traceEnd(TTRACE_TAG_WEB);
277 #endif
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;
281 }
282
283 }  // namespace ewk_interface
284
285 using namespace ewk_interface;
286
287 static void _ewk_force_acceleration() __attribute__((constructor));
288
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
294   // fail to execute.
295   setenv("ELM_ACCEL", "hw", 1);
296
297   // Chromium-efl does not support evasgl render thread feature yet.
298   setenv("EVAS_GL_DISABLE_RENDER_THREAD", "1", 1);
299 }
300
301 void* ewk_dlsym(const char* function_name) {
302 #if defined(ENABLE_WRT_JS) && BUILDFLAG(IS_TIZEN_TV)
303   TryOpenAppDefinedLib();
304 #endif
305
306   if (!g_impl_lib_handle && !open_library())
307     return nullptr;
308
309   void* function_addr = dlsym(g_impl_lib_handle, function_name);
310   if (!function_addr)
311     LOG(ERROR) << "No " << function_name << " symbol found! " << dlerror();
312
313   return function_addr;
314 }
315
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;
319
320   int ret = LwipcWaitEvent(kChromiumMountReady, timeout_msec);
321   if (ret == 0) {
322     LOG(INFO) << "chromium mount is done.";
323     return true;
324   }
325   LOG(ERROR) << "chromium mount is not ready yet: "
326              << (ret > 0 ? "timeout" : "fail");
327 #else
328   LOG(WARN) << "Not supported function";
329 #endif
330   return false;
331 }
332
333 Eina_Bool ewk_check_chromium_ready() {
334 #if BUILDFLAG(IS_TIZEN_TV)
335   LOG(INFO) << "ewk_check_chromium_ready called.";
336
337   if (LwipcIsDone(kChromiumMountReady) > 0) {
338     LOG(INFO) << "chromium mount is done.";
339     return true;
340   }
341   LOG(ERROR) << "chromium mount is not ready yet.";
342 #else
343   LOG(WARN) << "Not supported function";
344 #endif
345   return false;
346 }
347
348 int ewk_set_version_policy(int preference) {
349 #if BUILDFLAG(IS_TIZEN_TV)
350   int ret = preference;
351   if (0 == preference)
352     g_upgrade_lib = false;  // conservative
353   else if (1 == preference)
354     g_upgrade_lib = true;  // progressive
355   else {
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;
359   }
360   LOG(INFO) << "ewk_set_version_policy : " << ret;
361   typedef int (*func_ptr_t)(int);
362   func_ptr_t fp =
363       reinterpret_cast<func_ptr_t>(ewk_dlsym("ewk_set_version_policy"));
364   if (fp) {
365     return fp(preference);
366   } else if (g_upgrade_lib) {
367     // ignore request
368     LOG(ERROR) << "ewk_set_version_policy is not found. UWE request is ignored";
369     g_upgrade_lib = false;
370     return 0;
371   }
372   return ret;
373 #else
374   LOG(WARN) << "Not supported function";
375   return 1;
376 #endif
377 }
378
379 int ewk_init(void) {
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"));
383   if (fp)
384     return fp();
385   return 0;
386 }
387
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"));
392   if (fp)
393     return fp();
394   return 0;
395 }
396
397 #ifdef __cplusplus
398 extern "C" {
399 #endif
400
401 __attribute__((visibility("default"))) int efl_webprocess_main(
402     int argc,
403     const char** argv) {
404   LOG(INFO) << "EWK-INTERFACE : efl_webprocess_main called..";
405
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;
414         break;
415       }
416     }
417     LOG(INFO) << "Version policy : " << g_upgrade_lib;
418   }
419 #endif
420
421   typedef int (*func_ptr_t)(int argc, const char** argv);
422   func_ptr_t fp =
423       reinterpret_cast<func_ptr_t>(ewk_dlsym("efl_webprocess_main"));
424   if (fp)
425     return fp(argc, argv);
426   return 0;
427 }
428
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();
437   }
438   if (!MountDefaultChromiumImage() && !ewk_wait_chromium_ready(20000)) {
439     return 0;
440   }
441
442   if (IsFirstWrtLoader())
443     dlopen_mode = RTLD_NOW | RTLD_GLOBAL;
444
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
450       break;
451     }
452   }
453 #endif
454
455   typedef int (*func_ptr_t)(int argc, char** argv);
456   func_ptr_t fp = reinterpret_cast<func_ptr_t>(ewk_dlsym("WRTMain"));
457   if (fp)
458     return fp(argc, argv);
459   return 0;
460 }
461
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"));
467   if (fp)
468     return fp(argc, argv);
469   return 0;
470 }
471 #endif
472
473 #ifdef __cplusplus
474 }
475 #endif