From 26ba0912aac78eb121373cfe30cd803c96093fd3 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Fri, 6 Nov 2020 09:48:12 +0900 Subject: [PATCH 01/16] [Service] Terminate worker more gracefully process.exit() in node worker will call Worker::Exit(), which stop the thread asyncronously. So WorkerThreadData is released later after worker's exit event. worker.terminate() in main thread will call Worker::StopThread(), which processes Worker::JoinThread() as well as Worker::Exit(). JoinThread() can defer parent's exit() call after worker's gone. Change-Id: Iad6bd2d64f158e7d6734500a7ab0623d75ad630f Signed-off-by: DongHyun Song (cherry picked from commit 480b6888ff5a0e9fd5983788fc4a98d97e32e217) --- wrt_app/common/service_manager.ts | 5 +++++ wrt_app/common/service_runner.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index b48f2d4..a6ab24a 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -25,6 +25,11 @@ function createWorker(id: string, startService: string, filename: string) { filename } }); + workers[id].on('message', (message: string) => { + if (message === 'will-terminate') { + workers[id].terminate(); + } + }); workers[id].on('exit', (code: number) => { delete workers[id]; let runningServices = Object.keys(workers).length; diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index c3c8306..3e4b39e 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -102,7 +102,7 @@ function run() { stop(id); setTimeout(() => { XWalkExtension.cleanup(); - process.exit() + parentPort?.postMessage("will-terminate"); }, message.delay); } }); -- 2.7.4 From 27e18430914b56249e3bf8290170067004d65d3c Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Sun, 8 Nov 2020 20:12:31 +0900 Subject: [PATCH 02/16] [Service] Terminate node without process.exit() Node process will be terminated by uv handleres release instead of process.exit(). Related patch: https://review.tizen.org/gerrit/247203/ Change-Id: I24824ed1cc7ed9c055502d29a9008d27fedd3031 Signed-off-by: DongHyun Song (cherry picked from commit 9153d03dc5406e4e7017edcacdd81fa176d6490d) --- wrt_app/common/service_manager.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index b48f2d4..8fcb2e2 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -29,9 +29,6 @@ function createWorker(id: string, startService: string, filename: string) { delete workers[id]; let runningServices = Object.keys(workers).length; console.log(`exit code(${code}), remain services(${runningServices})`); - if (runningServices === 0 && isServiceApplication()) { - setTimeout(() => process.exit(), 500); - } }); } -- 2.7.4 From b6973a288994391aa43574138f81fa5faae7153c Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Fri, 6 Nov 2020 16:55:37 +0900 Subject: [PATCH 03/16] [Service] Prevent multiple calls of wrt.stopService() In case of RakutenTV app, it calls tizen.application...exit() twice. Of course WRTServiceManager::Remove() will skip stopService at the second time, this patch can skip stopService() sequence more early time. Change-Id: I65fdfb13f28834e4093f6be7888054e6aec7162b Signed-off-by: DongHyun Song (cherry picked from commit 9b0419b99033485731a603ac1bb96d1cc87ea7ee) --- wrt_app/common/service_runner.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index c3c8306..7825b02 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -34,7 +34,8 @@ function registerExtensionResolver(id: string) { } } -function requestStopService(id: string) { +let requestStopService = (id: string) => { + requestStopService = (id: string) => {}; setTimeout(() => wrt.stopService(id), 500); } -- 2.7.4 From 56f177237067a99f1b074dfe065847021e2567fd Mon Sep 17 00:00:00 2001 From: SangYong Park Date: Thu, 12 Nov 2020 15:04:33 +0900 Subject: [PATCH 04/16] Remove unnecessary cookie api Related patch: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/247660/ Change-Id: Ic5dc532cd2ce99df148398ad052e508e1e4fcdf4 Signed-off-by: SangYong Park --- wrt_app/src/runtime.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 0f81a53..42687a8 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -55,8 +55,6 @@ class Runtime { }); app.on('web-contents-created', (event, webContents) => { console.log('web-contents-created'); - if (wrt.tv) - this.setCookiePath(); webContents.on('before-input-event', (event, input) => { if (this.isLaunched && this.webApplication) this.handleKeyEvents(input.key); @@ -163,7 +161,6 @@ class Runtime { this.webApplication.sendAppControlEvent(); } } - this.setCookiePath(); this.launchInspector(appControl); }); wrt.on('suspend', () => { @@ -232,14 +229,6 @@ class Runtime { return (bundleDebug || this.inspectorEnabledByVconf); } - private setCookiePath() { - this.setCookiePath = () => {}; // call once - console.log('setCookiePath'); - - // FIX ME : It must be supplemented to set a specific path - wrt.setCookiePath(); - } - private handleKeyEvents(key: string) { let valid = false; console.log(key + ' is pressed'); -- 2.7.4 From dbae941c9eacebe10473e557fc7f181880e4f0f6 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 16 Nov 2020 14:10:57 +0900 Subject: [PATCH 05/16] [Service] Changes 'DAEMON' to 'GLOBAL' 'global' wrt-service is more common name than 'daemon' Related chromium-efl patch: https://review.tizen.org/gerrit/247741/ Change-Id: I9139832bc0cf4d2ce6a6b916c1e98ba984e4e5ed Signed-off-by: DongHyun Song --- wrt_app/common/service_runner.ts | 2 +- wrt_app/common/wrt_xwalk_extension.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index 3118d89..e8b912d 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -14,7 +14,7 @@ function isServiceApplication() { } function isGlobalService() { - return global['serviceType'] === 'DAEMON'; + return global['serviceType'] === 'GLOBAL'; } function registerExtensionResolver(id: string) { diff --git a/wrt_app/common/wrt_xwalk_extension.ts b/wrt_app/common/wrt_xwalk_extension.ts index f7ba13d..1204a81 100644 --- a/wrt_app/common/wrt_xwalk_extension.ts +++ b/wrt_app/common/wrt_xwalk_extension.ts @@ -118,7 +118,7 @@ class XWalkExtension { var api = (ext.use_trampoline) ? api_ : global; var extension_api = ext.jsapi; - if (global.serviceType === 'DAEMON' && ext.name === 'xwalk') { + if (global.serviceType === 'GLOBAL' && ext.name === 'xwalk') { console.log(`Delete freeze exports.utils for override method`); extension_api = extension_api.replace('Object.freeze(exports.utils);', ''); extension_api = extension_api.replace('Object.freeze(Utils.prototype);', ''); -- 2.7.4 From fdeb7353ba0fcdb884fecc9983c01107ee25753f Mon Sep 17 00:00:00 2001 From: "jaekuk, lee" Date: Tue, 17 Nov 2020 17:52:55 +0900 Subject: [PATCH 06/16] Don't display splash screen in background mode When launching app in backgroundAtStartup launchMode, prevent splash screen from being displayed. Change-Id: I416fce778e5a001df5a6da855959c88d42ac19f4 Signed-off-by: jaekuk, lee --- wrt_app/src/web_application.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 wrt_app/src/web_application.ts diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts old mode 100644 new mode 100755 index 430a593..8888289 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -285,7 +285,7 @@ export class WebApplication { this.suspended = false; if (this.showTimer) clearTimeout(this.showTimer); - let splashShown = firstLaunch && wrt.showSplashScreen(); + let splashShown = this.preloadStatus !== 'preload' && firstLaunch && wrt.showSplashScreen(); if (!splashShown && !wrt.tv) { this.showTimer = setTimeout(() => { if (!this.suspended) { -- 2.7.4 From 40e496ec570bbf6b9398438261e414cab84e763b Mon Sep 17 00:00:00 2001 From: Surya Kumar Date: Tue, 24 Nov 2020 12:51:23 +0530 Subject: [PATCH 07/16] [M85] Suppress a macOS hack present in electron to gain webview focus A hack used by electron meant for macOS & extended for other platforms contingently is causing behavior difference from XWALK. Since that's the only consumer of 'load-url', removed all event listeners. Focus will anyway be gained by WebContents on their respective show() calls. Fixes P200228-07034 & P200113-07900. Reference: https://review.tizen.org/gerrit/226898 Change-Id: Ife2e6fd54c146596becd5cd00fb86797a9dc6cae Signed-off-by: Surya Kumar --- wrt_app/browser/wrt_window.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrt_app/browser/wrt_window.ts b/wrt_app/browser/wrt_window.ts index 41c1690..2ac5a14 100644 --- a/wrt_app/browser/wrt_window.ts +++ b/wrt_app/browser/wrt_window.ts @@ -23,6 +23,9 @@ Object.setPrototypeOf(WRTWindow.prototype, BrowserWindow.prototype); WRTWindow.prototype._init = function () { (BrowserWindow.prototype as any)._init.call(this); + // This removes a macOS specific hack present in electron + // that causes side effects on Tizen + this.webContents.removeAllListeners('load-url'); if (typeof this.setup === 'function') this.setup(); this.constructor = BrowserWindow; -- 2.7.4 From 3b05de4cf0d609e050aa961f32458dd93cd163df Mon Sep 17 00:00:00 2001 From: Youngsoo Choi Date: Mon, 30 Nov 2020 22:24:21 -0800 Subject: [PATCH 08/16] Revert "[Service] Add edge orchestration interface" This reverts commit d55cc7de0b1ddb97a0eb533558fd51edb382763f. The edge interface is not ready yet on M85 chromium-efl. Change-Id: I1dfd008b4e6ebb4594aa7791ee2c5a58e43589a6 Signed-off-by: Youngsoo Choi --- wrt_app/service/device_api_router.ts | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index a7e3563..7cb70cb 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -52,34 +52,9 @@ export class DeviceAPIRouter { global.webapis.getPackageId = () => { return this.packageId; } - this.initEdgeWebapis(); this.initProductWebapis(); } - initEdgeWebapis() { - if (wrt['edge'] && !global.webapis.edge) { - let edge = wrt.edge as NativeWRTjs.EdgeExtension; - global.webapis.edge = { - orchestrationGetDevicelist: (service_name: string, exec_type: string) => { - return edge.orchestrationGetDevicelist(service_name, exec_type); - }, - orchestrationReadCapability: (ip: string) => { - return edge.orchestrationReadCapability(ip); - }, - orchestrationRequestService: (app_name: string, self_select: boolean, exec_type: string, exec_parameter: string) => { - return edge.orchestrationRequestService(app_name, self_select, exec_type, exec_parameter); - }, - orchestrationRequestServiceOnDevice: (app_name: string, self_select: boolean, exec_type: string, exec_parameter: string, ip: string) => { - return edge.orchestrationRequestServiceOnDevice(app_name, self_select, exec_type, exec_parameter, ip); - }, - orchestrationWriteCapability: (json: string) => { - return edge.orchestrationWriteCapability(json); - }, - } - Object.defineProperty(global.webapis, 'edge', { writable: false, enumerable: true }); - } - } - initProductWebapis() { // for TV profile if (wrt.tv && !global.webapis.productinfo) { -- 2.7.4 From cd6ebb4c5cceb62d2487af854dc9902d1b7b031d Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 23 Nov 2020 07:12:06 +0900 Subject: [PATCH 09/16] Refactor disk cache setting and appcontrol data Delete codes will be handled in native code side Related patch: https://review.tizen.org/gerrit/248127/ Change-Id: I596fce437f43664c4fd17eff959375d46ff7b776 Signed-off-by: DongHyun Song --- wrt_app/src/runtime.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 3717d43..185c63a 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -105,10 +105,6 @@ class Runtime { this.webApplication.inspectorSrc = src; src = "about:blank"; } - let useDiskCache = appControl.getData('USE_DISKCACHE'); - let halfWindowOption = appControl.getData('http://samsung.com/appcontrol/data/half_window_support'); - wrt.tv.setDiskCache(useDiskCache); - wrt.tv.handleAppControlData(launchMode, halfWindowOption); } this.webApplication.mainWindow.loadURL(src); this.webApplication.prelaunch(src); -- 2.7.4 From 08c4701f9f2e5a5f69a4bb257d846bf013fddcbd Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 2 Dec 2020 16:54:15 +0900 Subject: [PATCH 10/16] Make same function name with its event name 1) Rename functions same as its event name 2) Add blank line among functions. Change-Id: Ide74634ec37060572862e3983a953a54151a6fa5 Signed-off-by: DongHyun Song --- wrt_app/src/runtime.ts | 44 ++++++++++++++++++++++++++++-------------- wrt_app/src/web_application.ts | 38 ++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 3717d43..94f9e99 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -27,21 +27,24 @@ class Runtime { inspectorEnabledByVconf = false; constructor() { - app.on('before-quit', (event) => { + app.on('before-quit', (event: any) => { console.log('before-quit'); - this.webApplication?.quit(); + this.webApplication?.beforeQuit(); }); - app.on('will-quit', (event) => { + + app.on('will-quit', (event: any) => { console.log('will-quit'); addonManager.deactivateAll(); }); - app.on('quit', (event) => { + + app.on('quit', (event: any) => { console.log('quit'); if (this.webApplication) { - this.webApplication.finalize(); + this.webApplication.quit(); this.webApplication = undefined; } }); + app.on('browser-window-created', () => { console.log('browser-window-created'); if (!this.isLaunched) { @@ -49,18 +52,21 @@ class Runtime { this.isLaunched = true; } }); + app.on('window-all-closed', () => { console.log('window-all-closed'); app.quit(); }); - app.on('web-contents-created', (event, webContents) => { + + app.on('web-contents-created', (event: any, webContents: any) => { console.log('web-contents-created'); - webContents.on('before-input-event', (event, input) => { + webContents.on('before-input-event', (event: any, input: any) => { if (this.isLaunched && this.webApplication) this.handleKeyEvents(input.key); }); }); - app.once('ready', (event) => { + + app.once('ready', (event: any) => { console.log('ready'); let addonAvailable = addonManager.build(); console.log("addonBuild : " + addonAvailable); @@ -71,7 +77,8 @@ class Runtime { } wrt.tv?.importCertificate(''); }); - wrt.on('app-control', (event, appControl) => { + + wrt.on('app-control', (event: any, appControl: any) => { console.log('app-control'); let loadInfo = appControl.getLoadInfo(); let src = loadInfo.getSrc(); @@ -166,19 +173,23 @@ class Runtime { } this.launchInspector(appControl); }); + wrt.on('suspend', () => { console.log('suspend'); this.webApplication?.suspend(); }); + wrt.on('resume', () => { console.log('resume'); this.webApplication?.resume(); }); + wrt.on('low-memory', () => { console.log('low-memory'); this.webApplication?.lowMemory(); }); - wrt.on('message', (event, type, params) => { + + wrt.on('message', (event: any, type: string, params: string[]) => { console.log('message type(' + type + ') params : ' + params); const app_id = params[0]; if (type === 'startService') { @@ -189,21 +200,26 @@ class Runtime { event.preventDefault(); } }); + wrt.on('ambient-tick', () => { this.webApplication?.ambientTick(); }); - wrt.on('ambient-changed', (event, ambient_mode) => { + + wrt.on('ambient-changed', (event: any, ambient_mode: boolean) => { console.log('ambient-changed , ambient_mode:' + ambient_mode); this.webApplication?.ambientChanged(ambient_mode); }); - wrt.on('addon-installed', (event, path) => { + + wrt.on('addon-installed', (event: any, path: string) => { console.log('addon-installed at ' + path); addonManager.checkAddon(path); }); - wrt.on('addon-uninstalled', (event, id) => { + + wrt.on('addon-uninstalled', (event: any, id: string) => { console.log('addon-unistalled named ' + id); }); - wrt.on('wgt-checking-done', (event) => { + + wrt.on('wgt-checking-done', (event: any) => { console.log('wgt-checking-done'); addonManager.updateDB(); }); diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index 8888289..ce20833 100755 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -74,7 +74,7 @@ export class WebApplication { } private setupEventListener(options: RuntimeOption) { - app.on('browser-window-created', (event, window) => { + app.on('browser-window-created', (event: any, window: any) => { if (this.windowList.length > 0) this.windowList[this.windowList.length - 1].hide(); this.windowList.push(window); @@ -88,12 +88,14 @@ export class WebApplication { this.windowList[this.windowList.length - 1].show(); }); }); - app.on('web-contents-created', (event, webContents) => { + + app.on('web-contents-created', (event: any, webContents: any) => { webContents.on('crashed', function() { console.error('webContents crashed'); app.exit(100); }); - webContents.session.setPermissionRequestHandler((webContents, permission, callback) => { + + webContents.session.setPermissionRequestHandler((webContents: any, permission: string, callback: any) => { console.log(`handlePermissionRequests for ${permission}`); if (permission === 'notifications') { if (!this.notificationPermissionMap) @@ -127,7 +129,8 @@ export class WebApplication { } }); }); - app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { + + app.on('certificate-error', (event: any, webContents: any, url: string, error: string, certificate: any, callback: any) => { console.log('A certificate error has occurred'); event.preventDefault(); if (certificate.data) { @@ -140,7 +143,8 @@ export class WebApplication { callback(false); } }); - app.on('login', (event, webContents, request, authInfo, callback) => { + + app.on('login', (event: any, webContents: any, request: any, authInfo: any, callback: any) => { console.log(`Login info is required, isproxy: ${authInfo.isProxy}`); event.preventDefault(); let usrname = ''; @@ -165,9 +169,10 @@ export class WebApplication { wrt.handleAuthRequest(id, webContents); } }); + if (this.accessiblePath) { console.log(`accessiblePath: ${this.accessiblePath}`); - protocol.interceptFileProtocol('file', (request, callback) => { + protocol.interceptFileProtocol('file', (request: any, callback: any) => { if (request.url) { let parsed_info = new URL(request.url); let access_path = parsed_info.host + decodeURI(parsed_info.pathname); @@ -190,11 +195,12 @@ export class WebApplication { console.log('request url is empty'); (callback as any)(403); } - }, (error) => { + }, (error: Error) => { console.log(error); }); } - wrt.on('permission-response', (event, id, result) => { + + wrt.on('permission-response', (event: any, id: number, result: boolean) => { console.log(`permission-response for ${id} is ${result}`); let callback = this.pendingCallbacks.get(id); if (typeof callback === 'function') { @@ -203,7 +209,8 @@ export class WebApplication { this.pendingCallbacks.delete(id); } }); - wrt.on('auth-response', (event, id, submit, user, password) => { + + wrt.on('auth-response', (event: any, id: number, submit: boolean, user: string, password: string) => { let callback = this.pendingCallbacks.get(id); if (typeof callback === 'function') { console.log('calling auth response callback'); @@ -214,7 +221,8 @@ export class WebApplication { this.pendingCallbacks.delete(id); } }); - wrt.on('app-status-changed', (event, status) => { + + wrt.on('app-status-changed', (event: any, status: string) => { console.log(`runningStatus: ${status}, ${this.loadFinished}`); if (!wrt.tv) return; @@ -258,10 +266,12 @@ export class WebApplication { } this.show(); }); + this.mainWindow.webContents.on('did-start-loading', () => { console.log('webContents did-start-loading'); this.loadFinished = false; }); + this.mainWindow.webContents.on('did-finish-load', () => { console.log('webContents did-finish-load'); this.loadFinished = true; @@ -379,8 +389,8 @@ Then you can get profile log from the initial loading.`; this.windowList[this.windowList.length - 1].show(); } - finalize() { - console.log('WebApplication : finalize'); + quit() { + console.log('WebApplication : quit'); this.flushData(); this.windowList.forEach((window) => window.removeAllListeners()); this.inQuit = false; @@ -388,8 +398,8 @@ Then you can get profile log from the initial loading.`; this.suspend(); } - quit() { - console.log('WebApplication : quit'); + beforeQuit() { + console.log('WebApplication : beforeQuit'); addonManager.emit('lcQuit', this.mainWindow.id); if (wrt.tv) { this.inspectorSrc = ''; -- 2.7.4 From 943c25bda3bd3c48c94efd61d85182018292f54d Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 2 Dec 2020 17:14:35 +0900 Subject: [PATCH 11/16] Refactor app-control event to improve readability 1) Split into small functions by their roles. 2) Move functions to proper class - most of them are located in WebApplication Change-Id: Ibd03eb6b6ef29c197266b7b9d51393134c06c375 Signed-off-by: DongHyun Song --- wrt_app/src/runtime.ts | 127 ++++++++++++++--------------------------- wrt_app/src/web_application.ts | 86 +++++++++++++++++++++++++--- 2 files changed, 120 insertions(+), 93 deletions(-) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 8857abd..8687822 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -80,92 +80,16 @@ class Runtime { wrt.on('app-control', (event: any, appControl: any) => { console.log('app-control'); - let loadInfo = appControl.getLoadInfo(); - let src = loadInfo.getSrc(); - if (wrt.isElectronApp()) { - console.log('Electron App launch'); - const Module = require('module'); - Module.globalPaths.push(wrt.getAppPath()); - let filePath = src[7] === '/' ? src.substr(8) : src.substr(7); // strip "file://" - let pkgJson = require(filePath); - let pos = filePath.lastIndexOf('/'); - - let mainJsPath = (pos !== -1 ? filePath.substr(0, pos + 1) : '') + - (pkgJson.main || 'index.js'); - console.log('loading path:', mainJsPath); - Module._load(mainJsPath, Module, true); - app.emit('ready'); + this.handleAppControlForElectronApp(appControl); + return; + } + console.log('Tizen Web App launch'); + if (!this.webApplication) { + this.createWebApplicationAndLoadUrl(appControl); } else { - console.log('Tizen Web App launch'); - let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); - if (!this.webApplication) { - console.log('Creating WebApplication'); - let options: RuntimeOption = { - isAddonAvailable: addonManager.isAddonAvailable(), - launchMode: launchMode - } - this.webApplication = new WebApplication(options); - if (wrt.tv) { - this.inspectorEnabledByVconf = wrt.tv.needUseInspector(); - if (this.inspectorEnabledByVconf && launchMode != 'backgroundExecution') { - this.webApplication.inspectorSrc = src; - src = "about:blank"; - } - } - this.webApplication.mainWindow.loadURL(src); - this.webApplication.prelaunch(src); - if (wrt.da) { - this.webApplication.mainWindow.emit('ready-to-show'); - } - } else { - console.log('Handling app-control event'); - if (this.webApplication.preloadStatus == 'readyToShow') { - this.webApplication.show(); - } else { - if (launchMode != 'backgroundAtStartup') - this.webApplication.preloadStatus = 'none'; - } - - let skipReload = appControl.getData('SkipReload'); - if (skipReload == 'Yes') { - console.log('skipping reload'); - // TODO : Need to care this situation and decide to pass the addon event emitter to resume() - this.webApplication.resume(); - return; - } - - let reload = loadInfo.getReload() || this.webApplication.isAlwaysReload; - if (!reload) { - let originalUrl = this.webApplication.mainWindow.webContents.getURL(); - if (wrt.tv) { - console.log(`appcontrol src = ${src}, original url = ${originalUrl}`); - if (src && originalUrl) { - let appcontrolUrl = (new URL(src)).href; - let oldUrl = (new URL(originalUrl)).href; - console.log(`appcontrolUrl = ${appcontrolUrl}, oldUrl = ${oldUrl}`); - // FIXME(dh81.song) - // Below case it must be distinguishable for known cases - // from 'file:///index.htmlx' to 'file:///index.html' - if (appcontrolUrl !== oldUrl.substr(0, appcontrolUrl.length)) - reload = true; - } else { - reload = true; - } - } else if (src !== originalUrl) { - reload = true; - } - } - // handle http://tizen.org/appcontrol/operation/main operation specially. - // only menu-screen app can send launch request with main operation. - // in this case, web app should have to resume web app not reset. - if (reload && appControl.getOperation() == 'http://tizen.org/appcontrol/operation/main') - reload = false; - if (reload) - this.webApplication.handleAppControlReload(src); - else - this.webApplication.sendAppControlEvent(); - } + console.log('Handling app-control event'); + this.webApplication.handleAppControlEvent(appControl); } this.launchInspector(appControl); }); @@ -225,6 +149,41 @@ class Runtime { wrt.getInstalledPkg(); } + private handleAppControlForElectronApp(appControl: any) { + console.log('Electron App launch'); + let src = appControl.getLoadInfo().getSrc(); + const Module = require('module'); + Module.globalPaths.push(wrt.getAppPath()); + let filePath = src[7] === '/' ? src.substr(8) : src.substr(7); // strip "file://" + let pkgJson = require(filePath); + let pos = filePath.lastIndexOf('/'); + + let mainJsPath = (pos !== -1 ? filePath.substr(0, pos + 1) : '') + + (pkgJson.main || 'index.js'); + console.log('loading path:', mainJsPath); + Module._load(mainJsPath, Module, true); + app.emit('ready'); + } + + private createWebApplicationAndLoadUrl(appControl: any) { + console.log('Creating WebApplication'); + let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); + let src = appControl.getLoadInfo().getSrc(); + let options: RuntimeOption = { + isAddonAvailable: addonManager.isAddonAvailable(), + launchMode: launchMode + } + this.webApplication = new WebApplication(options); + if (wrt.tv) { + this.inspectorEnabledByVconf = wrt.tv.needUseInspector(); + if (this.inspectorEnabledByVconf && launchMode != 'backgroundExecution') { + this.webApplication.inspectorSrc = src; + src = "about:blank"; + } + } + this.webApplication.loadUrl(src); + } + private launchInspector(appControl: NativeWRTjs.AppControl) { this.launchInspector = (param) => {}; // call once console.log('launchInspector'); diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index ce20833..147ff8e 100755 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -27,7 +27,6 @@ export class WebApplication { backgroundExecution: boolean; defaultBackgroundColor: string; defaultTransparent: boolean; - isAlwaysReload: boolean; mainWindow: Electron.BrowserWindow; multitaskingSupport: boolean; notificationPermissionMap?: Map; @@ -60,7 +59,6 @@ export class WebApplication { this.backgroundExecution = false; } this.accessiblePath = wrt.tv?.getAccessiblePath(); - this.isAlwaysReload = (wrt.tv ? wrt.tv.isAlwaysReload() : false); this.multitaskingSupport = (wrt.tv ? wrt.tv.getMultitaskingSupport() : true); this.defaultBackgroundColor = (wrt.tv ? '#0000' : ((wrt.getPlatformType() === "product_wearable") ? '#000' : '#FFF')); @@ -312,13 +310,6 @@ export class WebApplication { return this.backgroundSupport || this.backgroundExecution; } - handleAppControlReload(url: string) { - console.log('WebApplication : handleAppControlReload'); - this.closeWindows(); - this.initDisplayDelay(false); - this.mainWindow.loadURL(url); - } - private suspendByStatus() { if (this.preloadStatus === 'readyToShow' || this.preloadStatus === 'preload' || @@ -354,6 +345,40 @@ Then you can get profile log from the initial loading.`; } } + handleAppControlEvent(appControl: any) { + let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); + this.handlePreloadState(launchMode); + + let skipReload = appControl.getData('SkipReload'); + if (skipReload == 'Yes') { + console.log('skipping reload'); + // TODO : Need to care this situation and decide to pass the addon event emitter to resume() + this.resume(); + return; + } + + let loadInfo = appControl.getLoadInfo(); + let src = loadInfo.getSrc(); + let reload = loadInfo.getReload() || this.needReload(src); + // handle http://tizen.org/appcontrol/operation/main operation specially. + // only menu-screen app can send launch request with main operation. + // in this case, web app should have to resume web app not reset. + if (reload && appControl.getOperation() == 'http://tizen.org/appcontrol/operation/main') + reload = false; + if (reload) + this.handleAppControlReload(src); + else + this.sendAppControlEvent(); + } + + loadUrl(src: string) { + this.mainWindow.loadURL(src); + this.prelaunch(src); + if (wrt.da) { + this.mainWindow.emit('ready-to-show'); + } + } + suspend() { if (this.suspended || this.inQuit) return; @@ -413,6 +438,49 @@ Then you can get profile log from the initial loading.`; this.inQuit = true; } + private needReload(src: string) { + let isAlwaysReload = (wrt.tv ? wrt.tv.isAlwaysReload() : false); + if (isAlwaysReload) { + return true; + } + let reload = false; + let originalUrl = this.mainWindow.webContents.getURL(); + if (wrt.tv) { + console.log(`appcontrol src = ${src}, original url = ${originalUrl}`); + if (src && originalUrl) { + let appcontrolUrl = (new URL(src)).href; + let oldUrl = (new URL(originalUrl)).href; + console.log(`appcontrolUrl = ${appcontrolUrl}, oldUrl = ${oldUrl}`); + // FIXME(dh81.song) + // Below case it must be distinguishable for known cases + // from 'file:///index.htmlx' to 'file:///index.html' + if (appcontrolUrl !== oldUrl.substr(0, appcontrolUrl.length)) + reload = true; + } else { + reload = true; + } + } else if (src !== originalUrl) { + reload = true; + } + return reload; + } + + private handleAppControlReload(url: string) { + console.log('WebApplication : handleAppControlReload'); + this.closeWindows(); + this.initDisplayDelay(false); + this.mainWindow.loadURL(url); + } + + private handlePreloadState(launchMode: string) { + if (this.preloadStatus == 'readyToShow') { + this.show(); + } else { + if (launchMode != 'backgroundAtStartup') + this.preloadStatus = 'none'; + } + } + private flushData() { console.log('WebApplication : FlushData'); this.windowList.forEach((window) => window.webContents.session.flushStorageData()); -- 2.7.4 From cd3319229afa5f538281631e503915922d794f78 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 16 Dec 2020 17:37:57 +0900 Subject: [PATCH 12/16] Move inspector functions to WebApplication debugPort / inspectorSrc are members for WebApplication class. Then, move related functions to WebApplication is more proper and it can reduce to check webApplication instance. Change-Id: I7fc4415e25249e574270a38900fdcb2bd1e934e7 Signed-off-by: DongHyun Song --- wrt_app/src/runtime.ts | 31 +------------------------------ wrt_app/src/web_application.ts | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 8687822..a729356 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -24,7 +24,6 @@ import { WebApplication } from './web_application'; class Runtime { webApplication?: WebApplication = undefined; isLaunched = false; - inspectorEnabledByVconf = false; constructor() { app.on('before-quit', (event: any) => { @@ -91,7 +90,6 @@ class Runtime { console.log('Handling app-control event'); this.webApplication.handleAppControlEvent(appControl); } - this.launchInspector(appControl); }); wrt.on('suspend', () => { @@ -168,39 +166,12 @@ class Runtime { private createWebApplicationAndLoadUrl(appControl: any) { console.log('Creating WebApplication'); let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); - let src = appControl.getLoadInfo().getSrc(); let options: RuntimeOption = { isAddonAvailable: addonManager.isAddonAvailable(), launchMode: launchMode } this.webApplication = new WebApplication(options); - if (wrt.tv) { - this.inspectorEnabledByVconf = wrt.tv.needUseInspector(); - if (this.inspectorEnabledByVconf && launchMode != 'backgroundExecution') { - this.webApplication.inspectorSrc = src; - src = "about:blank"; - } - } - this.webApplication.loadUrl(src); - } - - private launchInspector(appControl: NativeWRTjs.AppControl) { - this.launchInspector = (param) => {}; // call once - console.log('launchInspector'); - - // AUL public key/Vconf - To support inspector - if (this.checkInspectorCondition(appControl)) { - let debugPort = wrt.startInspectorServer(); - let data = { "port" : [ debugPort.toString() ] }; - if (this.webApplication) - this.webApplication.debugPort = debugPort; - appControl.reply(data); - } - } - - private checkInspectorCondition(appControl: NativeWRTjs.AppControl) { - let bundleDebug = (appControl.getData('__AUL_DEBUG__') === "1"); - return (bundleDebug || this.inspectorEnabledByVconf); + this.webApplication.loadUrl(appControl); } private handleKeyEvents(key: string) { diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index 147ff8e..25a2441 100755 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -36,6 +36,7 @@ export class WebApplication { backgroundSupport = wrt.getBackgroundSupport(); debugPort = 0; firstRendered = false; + contentSrc = ''; inspectorSrc = ''; loadFinished = false; pendingCallbacks: Map = new Map(); @@ -371,9 +372,27 @@ Then you can get profile log from the initial loading.`; this.sendAppControlEvent(); } - loadUrl(src: string) { - this.mainWindow.loadURL(src); - this.prelaunch(src); + private launchInspectorIfNeeded(appControl: NativeWRTjs.AppControl) { + console.log('launchInspectorIfNeeded'); + let inspectorEnabledByVconf = wrt.tv ? wrt.tv.needUseInspector() : false; + if (inspectorEnabledByVconf && !this.backgroundExecution) { + this.inspectorSrc = this.contentSrc; + this.contentSrc = 'about:blank'; + } + let hasAulDebug = (appControl.getData('__AUL_DEBUG__') === '1'); + if (hasAulDebug || inspectorEnabledByVconf) { + let debugPort = wrt.startInspectorServer(); + let data = { "port": [debugPort.toString()] }; + this.debugPort = debugPort; + appControl.reply(data); + } + } + + loadUrl(appControl: NativeWRTjs.AppControl) { + this.contentSrc = appControl.getLoadInfo().getSrc(); + this.launchInspectorIfNeeded(appControl); + this.mainWindow.loadURL(this.contentSrc); + this.prelaunch(this.contentSrc); if (wrt.da) { this.mainWindow.emit('ready-to-show'); } -- 2.7.4 From 121c9f9320b787159d5aff9ba84d169ffd224155 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 29 Dec 2020 17:45:21 +0900 Subject: [PATCH 14/16] [Service] Apply worker to 'standalone' model 'standalone' model will not be used anywhere. TV will apply global wrt-service on Tizen 6.5 Change-Id: I1ebe5fbea6a9db4f56c1d9fb0c58cfa7e76fdb63 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 14f0a87..face443 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -12,10 +12,6 @@ Object.defineProperty(global, 'serviceType', { writable: false }); -function isStandalone() { - return global['serviceType'] === 'STANDALONE'; -} - function createWorker(id: string, startService: string, filename: string) { if (workers[id]) return; @@ -49,26 +45,13 @@ function terminateWorker(id: string, delay: number) { export function startService(id: string, filename: string) { console.log(`startService - ${id}`); - if (isStandalone()) { - runner = require('../common/service_runner'); - runner.start(id, filename); - } else { - let startService = `${__dirname}/service_runner.js`; - createWorker(id, startService, filename); - } + let startService = `${__dirname}/service_runner.js`; + createWorker(id, startService, filename); } export function stopService(id: string) { console.log(`stopService - ${id}`); - if (isStandalone()) { - if (!runner) { - console.log('runner instance is null in standalone mode'); - return; - } - runner.stop(id); - } else { - terminateWorker(id, 500); - } + terminateWorker(id, 500); } export function handleBuiltinService(serviceId: string, serviceName: string) { -- 2.7.4 From 01d638f95796fba2fbc1e7a8dee138e00eb2543f Mon Sep 17 00:00:00 2001 From: liwei Date: Fri, 8 Jan 2021 17:52:11 +0800 Subject: [PATCH 15/16] [VD] Get app forcereload flag in webapplication constructor For wrt autotest tc which check "force.loadDefaultURI" metadata, get app forcereload flag(force.loadDefaultURI) in constructor, otherwise it's hard to make a scenario by test script to check this metadata. Change-Id: I38ae46846687ab52a874d8dff22d62f581b9491f Signed-off-by: liwei --- wrt_app/src/web_application.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) mode change 100755 => 100644 wrt_app/src/web_application.ts diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts old mode 100755 new mode 100644 index 25a2441..dee5636 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -27,6 +27,7 @@ export class WebApplication { backgroundExecution: boolean; defaultBackgroundColor: string; defaultTransparent: boolean; + isAlwaysReload: boolean; mainWindow: Electron.BrowserWindow; multitaskingSupport: boolean; notificationPermissionMap?: Map; @@ -60,6 +61,7 @@ export class WebApplication { this.backgroundExecution = false; } this.accessiblePath = wrt.tv?.getAccessiblePath(); + this.isAlwaysReload = (wrt.tv ? wrt.tv.isAlwaysReload() : false); this.multitaskingSupport = (wrt.tv ? wrt.tv.getMultitaskingSupport() : true); this.defaultBackgroundColor = (wrt.tv ? '#0000' : ((wrt.getPlatformType() === "product_wearable") ? '#000' : '#FFF')); @@ -458,8 +460,7 @@ Then you can get profile log from the initial loading.`; } private needReload(src: string) { - let isAlwaysReload = (wrt.tv ? wrt.tv.isAlwaysReload() : false); - if (isAlwaysReload) { + if (this.isAlwaysReload) { return true; } let reload = false; -- 2.7.4 From 486ed93ebf9d237de154cd431219727f46221e42 Mon Sep 17 00:00:00 2001 From: liwei Date: Fri, 15 Jan 2021 10:19:22 +0800 Subject: [PATCH 16/16] [Tizen6.5 Migration][Service] Print appcontrol data when service app is launched Now in many scenario UI app launch service app, service app will check tizen.application.getCurrentApplication().getRequestedAppControl() operation and data, so print this data is good for debugging. (ex. 3201506003227, STARZY) Related patch: https://review.tizen.org/gerrit/248053/ Change-Id: I9f7b6c6319ddc0e16089ef826855ce064aeb754f Signed-off-by: liwei --- wrt_app/common/service_runner.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index 8913929..4a0d1f1 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -16,6 +16,15 @@ function isServiceApplication() { function isGlobalService() { return global['serviceType'] === 'GLOBAL'; } +function printAppControlData(id: string) { + var reqAppControl = global.tizen.application.getCurrentApplication().getRequestedAppControl(); + var appControlData = reqAppControl.appControl.data; + console.log(`id: ${id}, appControlData operation: ${reqAppControl.appControl.operation}`); + for (var dataIndex in appControlData) { + for (var valueIndex in appControlData[dataIndex].value) + console.log(`data[${dataIndex}][${valueIndex}]: ${appControlData[dataIndex].value[valueIndex]}`); + } +} function registerExtensionResolver(id: string) { if (wrt.tv) { @@ -63,6 +72,7 @@ export function start(id: string, filename: string) { // FIXME: this is for awaking up uv loop. // uv loop is sleeping for a few second with tizen webapis's aync callback fakeTimer = setInterval(() => {}, 100); + printAppControlData(id); try { app = require(filename); if (app.onStart !== undefined) { -- 2.7.4