From dd79b18738cdb66f003a5195e78b5ff03248e27e Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 13 Oct 2020 10:20:10 +0900 Subject: [PATCH 01/16] [Service] Refactor stop service sequence When service application needs to terminate by tizen://exit, it should call wrt.stopService(id). However, it is called in worker thread with standalone model, WRTServiceManager::Remove() will be handled in worker thread, not main thread. then, uv loop sometimes makes abort() or get SIGSEGV. Then, wrt.stopService(id) should be called in main thread side. Change-Id: I103bf8f38111db984bb22d0af56c05456851b681 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 15 ++++++++++++--- wrt_app/common/service_runner.ts | 11 ++++++++--- wrt_app/service/builtins/wasm_builder.ts | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index c4b2940..beb3d6e 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -43,7 +43,13 @@ export function startService(id: string, filename: string) { console.log(`startService - ${id}`); if (isMainThread) { let startService = `${__dirname}/service_runner.js`; - createWorker(id, startService, filename); + let worker = createWorker(id, startService, filename); + worker.on('message', (message: any) => { + if (message.type === 'stop') { + console.log(`${id} will shutdown after ${message.delay}ms`); + setTimeout(() => wrt.stopService(id), message.delay); + } + }); } } @@ -64,8 +70,11 @@ export function handleBuiltinService(serviceId: string, serviceName: string) { console.log(`Builtin service is ${serviceName}`); let startService = `${__dirname}/../service/builtins/${serviceName}.js`; let worker = createWorker(serviceId, startService, ''); - worker.on('stop', () => { - terminateWorker(serviceId, 0); + worker.on('message', (message: any) => { + if (message.type === 'stop') { + console.log(`${serviceName} built-in service will be stopped`); + terminateWorker(serviceId, message.delay); + } }); } } diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index 43681b5..c86829c 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -31,13 +31,18 @@ function registerExtensionResolver(id: string) { } } +function requestStopService(delay: number) { + if (parentPort) { + parentPort.postMessage({type: 'stop', delay: delay}); + } +} + let app: any = null; export function start(id: string, filename: string) { XWalkExtension.initialize(); XWalkExtension.setRuntimeMessageHandler((type, data) => { if (type === 'tizen://exit') { - console.log(`${id} will be closed by ${type}`); - setTimeout(() => wrt.stopService(id), 500); + requestStopService(500); } }); @@ -66,7 +71,7 @@ export function start(id: string, filename: string) { } } catch (e) { console.log(`exception on start: ${e}`); - setTimeout(() => wrt.stopService(id), 500); + requestStopService(500); } } diff --git a/wrt_app/service/builtins/wasm_builder.ts b/wrt_app/service/builtins/wasm_builder.ts index 7ec30a3..6f6c5b1 100644 --- a/wrt_app/service/builtins/wasm_builder.ts +++ b/wrt_app/service/builtins/wasm_builder.ts @@ -26,7 +26,7 @@ export function run(app_id: string) { compileWasmForCaching(file_path); }); if (parentPort) { - parentPort.postMessage('stop'); + parentPort.postMessage({type: 'stop', delay: 0}); } } -- 2.7.4 From 05fa491405a2c70ee695c89d06817197dcc5bab6 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 29 Sep 2020 11:47:49 +0900 Subject: [PATCH 02/16] Remove wrt.tv.flushCookie() flushCookie() will be called on WRTCookieManager's dtor. flushStorageData() is applied for all profile. Related chromium-efl patch: https://review.tizen.org/gerrit/245001/ Change-Id: Ic339b7d639c76dd5829c1a8f0ba0bd1d24941823 --- wrt_app/src/web_application.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index 61bbfd7..4310ed4 100644 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -398,10 +398,7 @@ Then you can get profile log from the initial loading.`; private flushData() { console.log('WebApplication : FlushData'); - if (wrt.tv) { - wrt.tv.flushCookie(); - this.windowList.forEach((window) => window.webContents.session.flushStorageData()); - } + this.windowList.forEach((window) => window.webContents.session.flushStorageData()); } sendAppControlEvent() { -- 2.7.4 From 12ff1412f2c81ffce556a1ad5756d42996434898 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 13 Oct 2020 08:14:25 +0000 Subject: [PATCH 03/16] Revert "[Service] Refactor stop service sequence" This reverts commit dd79b18738cdb66f003a5195e78b5ff03248e27e. Change-Id: If6ff1a847e9aeed86faf9fd9fc014971c339096f --- wrt_app/common/service_manager.ts | 15 +++------------ wrt_app/common/service_runner.ts | 11 +++-------- wrt_app/service/builtins/wasm_builder.ts | 2 +- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index beb3d6e..c4b2940 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -43,13 +43,7 @@ export function startService(id: string, filename: string) { console.log(`startService - ${id}`); if (isMainThread) { let startService = `${__dirname}/service_runner.js`; - let worker = createWorker(id, startService, filename); - worker.on('message', (message: any) => { - if (message.type === 'stop') { - console.log(`${id} will shutdown after ${message.delay}ms`); - setTimeout(() => wrt.stopService(id), message.delay); - } - }); + createWorker(id, startService, filename); } } @@ -70,11 +64,8 @@ export function handleBuiltinService(serviceId: string, serviceName: string) { console.log(`Builtin service is ${serviceName}`); let startService = `${__dirname}/../service/builtins/${serviceName}.js`; let worker = createWorker(serviceId, startService, ''); - worker.on('message', (message: any) => { - if (message.type === 'stop') { - console.log(`${serviceName} built-in service will be stopped`); - terminateWorker(serviceId, message.delay); - } + worker.on('stop', () => { + terminateWorker(serviceId, 0); }); } } diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index c86829c..43681b5 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -31,18 +31,13 @@ function registerExtensionResolver(id: string) { } } -function requestStopService(delay: number) { - if (parentPort) { - parentPort.postMessage({type: 'stop', delay: delay}); - } -} - let app: any = null; export function start(id: string, filename: string) { XWalkExtension.initialize(); XWalkExtension.setRuntimeMessageHandler((type, data) => { if (type === 'tizen://exit') { - requestStopService(500); + console.log(`${id} will be closed by ${type}`); + setTimeout(() => wrt.stopService(id), 500); } }); @@ -71,7 +66,7 @@ export function start(id: string, filename: string) { } } catch (e) { console.log(`exception on start: ${e}`); - requestStopService(500); + setTimeout(() => wrt.stopService(id), 500); } } diff --git a/wrt_app/service/builtins/wasm_builder.ts b/wrt_app/service/builtins/wasm_builder.ts index 6f6c5b1..7ec30a3 100644 --- a/wrt_app/service/builtins/wasm_builder.ts +++ b/wrt_app/service/builtins/wasm_builder.ts @@ -26,7 +26,7 @@ export function run(app_id: string) { compileWasmForCaching(file_path); }); if (parentPort) { - parentPort.postMessage({type: 'stop', delay: 0}); + parentPort.postMessage('stop'); } } -- 2.7.4 From a3646fe3fdc71541b00cf057feb2a8a46e346f48 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 13 Oct 2020 08:14:52 +0000 Subject: [PATCH 04/16] Revert "[Service] Apply node worker for standalone model" This reverts commit 2b011acf4a65ec8b940605ddeb53cc3709f2009d. Change-Id: I4203e460734b8befd84a2286663ae6c41a7b3232 --- wrt_app/common/service_manager.ts | 33 ++++++++++++++++++++++++++------- wrt_app/service/main.ts | 3 +++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index c4b2940..3038364 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -5,11 +5,16 @@ interface WorkerMap { [id: string]: any; } let workers: WorkerMap = {}; +let runner: any; global.serviceType = wrt.getServiceModel(); -function isServiceApplication() { - return global.serviceType !== 'UI'; +function isStandalone() { + return global.serviceType === 'STANDALONE'; +} + +function isGlobalService() { + return global.serviceType === 'DAEMON'; } function createWorker(id: string, startService: string, filename: string) { @@ -32,7 +37,7 @@ function terminateWorker(id: string, delay: number) { delete workers[id]; let runningServices = Object.keys(workers).length; console.log('Running services : ' + runningServices); - if (runningServices === 0 && isServiceApplication()) { + if (runningServices === 0 && isGlobalService()) { process.exit(); } } @@ -41,15 +46,29 @@ function terminateWorker(id: string, delay: number) { export function startService(id: string, filename: string) { console.log(`startService - ${id}`); - if (isMainThread) { - let startService = `${__dirname}/service_runner.js`; - createWorker(id, startService, filename); + if (isStandalone()) { + runner = require('../common/service_runner'); + runner.start(id, filename); + } else { + if (isMainThread) { + let startService = `${__dirname}/service_runner.js`; + createWorker(id, startService, filename); + } } } export function stopService(id: string) { console.log(`stopService - ${id}`); - terminateWorker(id, 500); + if (isStandalone()) { + if (!runner) { + console.log('runner instance is null in standalone mode'); + return; + } + runner.stop(id); + setTimeout(() => process.exit(), 500); + } else { + terminateWorker(id, 500); + } } export function handleBuiltinService(serviceId: string, serviceName: string) { diff --git a/wrt_app/service/main.ts b/wrt_app/service/main.ts index c64591e..b0c371a 100755 --- a/wrt_app/service/main.ts +++ b/wrt_app/service/main.ts @@ -27,6 +27,9 @@ wrt.on('start-service', (event: any, internal_id: string) => { wrt.on('stop-service', (event: any, internal_id: string) => { ServiceManager.stopService(internal_id); + if (wrt.getServiceModel() === 'STANDALONE') { + setTimeout(() => {process.exit()}, 10); + } }); wrt.on('builtin-service', (event: any, internal_id: string, service_name: string) => { -- 2.7.4 From 8b7fec189a3c571f4b56ff318b51c7f18cd21651 Mon Sep 17 00:00:00 2001 From: liwei Date: Mon, 28 Sep 2020 15:35:21 +0800 Subject: [PATCH 05/16] [Service][TV] Support more webapis.productinfo Support webapis.productinfo.is8KPanelSupported() / isUHDAModel() / getSmartTVServerType() / isWallModel() Native Patch: https://review.tizen.org/gerrit/244962/ Change-Id: Icdd34cf44338a8d5b92bfad1c98cd96b07309b4a Signed-off-by: liwei --- wrt_app/service/device_api_router.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index 4ccf2ef..8884fb3 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -87,8 +87,26 @@ export class DeviceAPIRouter { }, getSmartTVServerVersion: () => { return getCachedValue('getSmartTVServerVersion'); + }, + getSmartTVServerType: () => { + return Number(getCachedValue('getSmartTVServerType')); + }, + isWallModel: () => { + return (getCachedValue('isWallModel') === 'true'); + }, + isUHDAModel: () => { + return (getCachedValue('isUHDAModel') === 'true'); + }, + is8KPanelSupported: () => { + return (getCachedValue('is8KPanelSupported') === 'true'); } }; + + global.webapis.productinfo.ProductInfoSiServerType = { + SI_TYPE_OPERATIING_SERVER: 0, + SI_TYPE_DEVELOPMENT_SERVER: 1, + SI_TYPE_DEVELOPING_SERVER: 2 + }; } } -- 2.7.4 From 25de0d7b52383ecec883b6b88be004d269edf2ed Mon Sep 17 00:00:00 2001 From: Youngsoo Choi Date: Mon, 19 Oct 2020 05:11:03 -0700 Subject: [PATCH 06/16] [Service] Make appInfo writable In follwing sample code, The appInfo needs to be writable with application information having app id 'TCT_APPCONTROL_APPID' as TC expected. > var app = tizen.application.getCurrentApplication(); > app.appInfo = > tizen.application.getAppInfo(application_common.TCT_APPCONTROL_APPID); Change-Id: I6d89d5d1c0d9c241cebc5ff92b15167c890f1a55 Signed-off-by: Youngsoo Choi --- wrt_app/service/device_api_router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index 4ccf2ef..546c3a4 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -149,7 +149,7 @@ export class DeviceAPIRouter { version: { writable: false, enumerable: true } }); Object.defineProperties(this.currentApplication, { - appInfo: { writable: false, enumerable: true }, + appInfo: { enumerable: true }, contextId: { writable: false, enumerable: true } }); // tizen.application.getCurrentApplication().getRequestedAppControl() @@ -168,7 +168,7 @@ export class DeviceAPIRouter { let app_id = args[0]; if (this.hasNoneOrNull(args)) app_id = this.getServiceId(); - console.log(`Routing - getAppInfo()`); + console.log(`Routing - getAppInfo(${app_id})`); return this.funcGetAppInfo(app_id); } // tizen.application.getAppCerts() -- 2.7.4 From bc1291eeb6f7ae34a867faf97b04e01ed05e1233 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 13 Oct 2020 19:03:27 +0900 Subject: [PATCH 07/16] [Service][Reland] Apply node worker for standalone model This patch includes below, 1) unify source code with global model. 2) isolate v8 variable scope from main thread. - standalone service application cannot get main global variable. of service_manaer / service_runner 3) refactor handling message with node worker. 4) refactor termination sequence of node worker more gracefully. - process.exit() is invoked by worker side - parent handles on('exit') for clean-up Additionally, there is no noticeable memory increase with node worker. References: https://review.tizen.org/gerrit/244938/ https://review.tizen.org/gerrit/245591/ Change-Id: Ie9c17b373a69585ca755e39c4ab56243406821a2 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 77 ++++++++++++-------------------- wrt_app/common/service_runner.ts | 30 ++++++++----- wrt_app/service/builtins/wasm_builder.ts | 22 +++++---- wrt_app/service/main.ts | 6 +-- 4 files changed, 60 insertions(+), 75 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 3038364..b48f2d4 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -5,25 +5,34 @@ interface WorkerMap { [id: string]: any; } let workers: WorkerMap = {}; -let runner: any; -global.serviceType = wrt.getServiceModel(); +Object.defineProperty(global, 'serviceType', { + value: wrt.getServiceModel(), + writable: false +}); -function isStandalone() { - return global.serviceType === 'STANDALONE'; -} - -function isGlobalService() { - return global.serviceType === 'DAEMON'; +function isServiceApplication() { + return global['serviceType'] !== 'UI'; } function createWorker(id: string, startService: string, filename: string) { - return workers[id] ?? (workers[id] = new Worker(startService, { + if (workers[id]) + return; + + workers[id] = new Worker(startService, { workerData: { id, filename } - })); + }); + workers[id].on('exit', (code: number) => { + 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); + } + }); } function terminateWorker(id: string, delay: number) { @@ -31,44 +40,19 @@ function terminateWorker(id: string, delay: number) { console.log(`This worker is already terminated. ${id}`); return; } - workers[id].postMessage('stopService'); - let terminate = () => { - workers[id].terminate(); - delete workers[id]; - let runningServices = Object.keys(workers).length; - console.log('Running services : ' + runningServices); - if (runningServices === 0 && isGlobalService()) { - process.exit(); - } - } - setTimeout(() => terminate(), delay); + console.log(`${id} will shutdown after ${delay}ms`); + workers[id].postMessage({ type: 'stop', delay }); } export function startService(id: string, filename: string) { console.log(`startService - ${id}`); - if (isStandalone()) { - runner = require('../common/service_runner'); - runner.start(id, filename); - } else { - if (isMainThread) { - 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); - setTimeout(() => process.exit(), 500); - } else { - terminateWorker(id, 500); - } + terminateWorker(id, 500); } export function handleBuiltinService(serviceId: string, serviceName: string) { @@ -77,15 +61,10 @@ export function handleBuiltinService(serviceId: string, serviceName: string) { } let need_stop = (serviceName.substr(0, 5) === 'stop_'); if (need_stop) { - terminateWorker(serviceId, 0); + workers[serviceId].terminate(); } else { - if (isMainThread) { - console.log(`Builtin service is ${serviceName}`); - let startService = `${__dirname}/../service/builtins/${serviceName}.js`; - let worker = createWorker(serviceId, startService, ''); - worker.on('stop', () => { - terminateWorker(serviceId, 0); - }); - } + console.log(`Builtin service is ${serviceName}`); + let startService = `${__dirname}/../service/builtins/${serviceName}.js`; + createWorker(serviceId, startService, ''); } } \ No newline at end of file diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index 43681b5..c3c8306 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -4,14 +4,17 @@ import { DeviceAPIRouter } from '../service/device_api_router'; import { isMainThread, parentPort, workerData } from 'worker_threads'; import { wrt } from '../browser/wrt'; -global.serviceType = wrt.getServiceModel(); +Object.defineProperty(global, 'serviceType', { + value: wrt.getServiceModel(), + writable: false +}); function isServiceApplication() { - return global.serviceType !== 'UI'; + return global['serviceType'] !== 'UI'; } function isGlobalService() { - return global.serviceType === 'DAEMON'; + return global['serviceType'] === 'DAEMON'; } function registerExtensionResolver(id: string) { @@ -31,17 +34,21 @@ function registerExtensionResolver(id: string) { } } +function requestStopService(id: string) { + setTimeout(() => wrt.stopService(id), 500); +} + let app: any = null; export function start(id: string, filename: string) { XWalkExtension.initialize(); XWalkExtension.setRuntimeMessageHandler((type, data) => { if (type === 'tizen://exit') { console.log(`${id} will be closed by ${type}`); - setTimeout(() => wrt.stopService(id), 500); + requestStopService(id); } }); - console.log(`serviceType : ${global.serviceType}`) + console.log(`serviceType : ${global['serviceType']}`) new DeviceAPIRouter(id, isGlobalService()); if (isServiceApplication()) { @@ -66,7 +73,7 @@ export function start(id: string, filename: string) { } } catch (e) { console.log(`exception on start: ${e}`); - setTimeout(() => wrt.stopService(id), 500); + requestStopService(id); } } @@ -89,11 +96,14 @@ function run() { if (!parentPort) return; - parentPort.on('message', (msg) => { - console.log(`message received : ${msg}`); - if (msg === 'stopService') { + parentPort.on('message', (message) => { + console.log(`Received message type : ${message.type}`); + if (message.type === 'stop') { stop(id); - XWalkExtension.cleanup(); + setTimeout(() => { + XWalkExtension.cleanup(); + process.exit() + }, message.delay); } }); } diff --git a/wrt_app/service/builtins/wasm_builder.ts b/wrt_app/service/builtins/wasm_builder.ts index 7ec30a3..54177d0 100644 --- a/wrt_app/service/builtins/wasm_builder.ts +++ b/wrt_app/service/builtins/wasm_builder.ts @@ -3,12 +3,14 @@ import { isMainThread, parentPort, workerData } from 'worker_threads'; import { wrt } from '../../browser/wrt'; import * as fs from 'fs'; -async function compileWasmForCaching(file_path: string) { - console.log(`Requesting WASM compilation for building a cache, file_path:(${file_path})`); +function compileWasmForCaching(files: string[]) { try { - let source = fs.readFileSync(file_path); - let file = new Uint8Array(source); - await WebAssembly.compile(file); + files.forEach(async file_path => { + console.log(`Requesting WASM compilation for building a cache, file_path:(${file_path})`); + let source = fs.readFileSync(file_path); + let file = new Uint8Array(source); + await WebAssembly.compile(file); + }); } catch (e) { console.error(`An error occurred while compiling a wasm module. error:(${e})`); } @@ -21,13 +23,9 @@ export function run(app_id: string) { tv.setDiskCache(app_id); let files = tv.getWasmFiles(app_id); console.log(files); - files.forEach((file_path: string) => { - tv.delayShutdown(); - compileWasmForCaching(file_path); - }); - if (parentPort) { - parentPort.postMessage('stop'); - } + tv.delayShutdown(); + compileWasmForCaching(files); + process.exit(); } if (!isMainThread) { diff --git a/wrt_app/service/main.ts b/wrt_app/service/main.ts index b0c371a..6e6c222 100755 --- a/wrt_app/service/main.ts +++ b/wrt_app/service/main.ts @@ -21,15 +21,13 @@ import { wrt } from '../browser/wrt'; import * as ServiceManager from '../common/service_manager'; wrt.on('start-service', (event: any, internal_id: string) => { - console.log('start service app : ' + internal_id); + console.log(`start service app : ${internal_id}`); ServiceManager.startService(internal_id, ''); }); wrt.on('stop-service', (event: any, internal_id: string) => { + console.log(`stop service app : ${internal_id}`); ServiceManager.stopService(internal_id); - if (wrt.getServiceModel() === 'STANDALONE') { - setTimeout(() => {process.exit()}, 10); - } }); wrt.on('builtin-service', (event: any, internal_id: string, service_name: string) => { -- 2.7.4 From d75ae6696e935369ebe7c7c8fe3406438b73fc97 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 21 Oct 2020 15:21:48 +0900 Subject: [PATCH 08/16] [TV] Remove unnecessary code clearDeadMount() was removed from https://review.tizen.org/gerrit/245799/ Change-Id: I56d6198754962d24131b318ddb986e96f355ceac Signed-off-by: DongHyun Song --- wrt_app/src/runtime.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 02a15b6..0f81a53 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -71,10 +71,7 @@ class Runtime { XWalkExtension.initialize(); XWalkExtension.preventCleanup(); } - if (wrt.tv) { - wrt.tv.importCertificate(''); - wrt.tv.clearDeadMount(); - } + wrt.tv?.importCertificate(''); }); wrt.on('app-control', (event, appControl) => { console.log('app-control'); -- 2.7.4 From f4efaad9398a07f2d1716a806fdc7d8a6578d196 Mon Sep 17 00:00:00 2001 From: "k2.nagaraju" Date: Mon, 19 Oct 2020 21:05:06 +0530 Subject: [PATCH 09/16] [Service] Exception is throwing if argument length is 0 Calling |resolveVirtualRoot| with |0| parameter throwing exception, which is causing failure in service filesystem webtct. Change-Id: I5e8d54f916d408145331066b31f7432ad7a3be55 Signed-off-by: k2.nagaraju --- wrt_app/service/device_api_router.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index 4ccf2ef..7d08190 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -228,9 +228,11 @@ export class DeviceAPIRouter { injectVirtualRootResolver(func: Function) { return (...args: any[]) => { - console.log(args); - args[0] = wrt.resolveVirtualRoot(this.getServiceId(), args[0]); - console.log(args[0]); + console.log('arguments : ' + args); + if (args.length && !(args[0] === null || args[0] === undefined)) { + args[0] = wrt.resolveVirtualRoot(this.getServiceId(), args[0]); + console.log('updated argument[0] : ' + args[0]); + } return func.apply(global.tizen.filesystem, args); } } @@ -239,7 +241,6 @@ export class DeviceAPIRouter { global.tizen.filesystem.resolve = this.injectVirtualRootResolver(global.tizen.filesystem.resolve); global.tizen.filesystem.listDirectory = this.injectVirtualRootResolver(global.tizen.filesystem.listDirectory); global.tizen.filesystem.createDirectory = this.injectVirtualRootResolver(global.tizen.filesystem.createDirectory); - global.tizen.filesystem.createDirectory = this.injectVirtualRootResolver(global.tizen.filesystem.createDirectory); global.tizen.filesystem.deleteDirectory = this.injectVirtualRootResolver(global.tizen.filesystem.deleteDirectory); global.tizen.filesystem.openFile = this.injectVirtualRootResolver(global.tizen.filesystem.openFile); global.tizen.filesystem.deleteFile = this.injectVirtualRootResolver(global.tizen.filesystem.deleteFile); -- 2.7.4 From ba115a874e610dc86953a45ef7da2b0627412e46 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 22 Oct 2020 14:15:08 +0900 Subject: [PATCH 10/16] Refactor suspend sequence 1) Bring forward suspend time when before-quit. ** When OnTerminate is coming first earlier than OnPause, 'quit' makes this.webApplication as undefined, then wrt.on('suspend'...) will be skipped. This means that With normal termination sequence, suspending might be not handled. 2) Even though background runnable app, when app is in quitting, enable suspend sequence for right termination sequence. Change-Id: Ie40f650ea317d6f198f9c1c1aa07c9bc6867b693 Signed-off-by: DongHyun Song --- wrt_app/src/web_application.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index 61bbfd7..3e5a683 100644 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -44,6 +44,7 @@ export class WebApplication { runningStatus = 'none'; suspended = false; windowList: Electron.BrowserWindow[] = []; + inQuit = false; constructor(options: RuntimeOption) { if (options.launchMode == 'backgroundAtStartup') { @@ -344,12 +345,14 @@ Then you can get profile log from the initial loading.`; } suspend() { + if (this.suspended) + return; console.log('WebApplication : suspend'); addonManager.emit('lcSuspend', this.mainWindow.id); this.suspended = true; this.windowList[this.windowList.length - 1].hide(); this.flushData(); - if (!this.backgroundRunnable()) { + if (!this.backgroundRunnable() || this.inQuit) { if (!this.multitaskingSupport) { // FIXME : terminate app after visibilitychange event handling setTimeout(() => { @@ -394,6 +397,9 @@ Then you can get profile log from the initial loading.`; quit() { console.log('WebApplication : quit'); addonManager.emit('lcQuit', this.mainWindow.id); + this.inQuit = true; + if (!this.suspended) + this.suspend(); } private flushData() { -- 2.7.4 From ada818484187c865d14400baa1b6a4308478f2cb Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 12 Oct 2020 17:32:23 +0900 Subject: [PATCH 11/16] [TV] Bring cancelDialogs() forward to before-quit With below refactor patch, https://review.tizen.org/gerrit/245417/ Defered timing of closing windows, Sometimes, JS exception is coming due to access of destroyed Object at wrt.tv.cancelDialogs(this.mainWindow.webContents); Change-Id: I207c890cb84e6aaec8ed13316c39b80dd2e6cd3c Signed-off-by: DongHyun Song --- wrt_app/src/web_application.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index 3e5a683..3795a2a 100644 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -381,22 +381,22 @@ Then you can get profile log from the initial loading.`; finalize() { console.log('WebApplication : finalize'); + this.flushData(); + this.windowList.forEach((window) => window.removeAllListeners()); + } + + quit() { + console.log('WebApplication : quit'); + addonManager.emit('lcQuit', this.mainWindow.id); if (wrt.tv) { this.inspectorSrc = ''; wrt.tv.cancelDialogs(this.mainWindow.webContents); } - this.flushData(); if (this.debugPort) { console.log('stop inspector server'); this.debugPort = 0; wrt.stopInspectorServer(); } - this.windowList.forEach((window) => window.removeAllListeners()); - } - - quit() { - console.log('WebApplication : quit'); - addonManager.emit('lcQuit', this.mainWindow.id); this.inQuit = true; if (!this.suspended) this.suspend(); -- 2.7.4 From 4c869fc6fd8fd46090a6919ee53b69df7283f353 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 26 Oct 2020 19:07:57 +0900 Subject: [PATCH 12/16] Refactor suspend sequence To guarantee unload* events, suspend() should be deffered after closing windows. Related patch: https://review.tizen.org/gerrit/246015/ https://review.tizen.org/gerrit/245417/ Change-Id: Id13a275b64e75f985e0115eee6771e3c29dd9cd9 Signed-off-by: DongHyun Song --- wrt_app/src/web_application.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wrt_app/src/web_application.ts b/wrt_app/src/web_application.ts index 3795a2a..5a57298 100644 --- a/wrt_app/src/web_application.ts +++ b/wrt_app/src/web_application.ts @@ -345,14 +345,14 @@ Then you can get profile log from the initial loading.`; } suspend() { - if (this.suspended) + if (this.suspended || this.inQuit) return; console.log('WebApplication : suspend'); addonManager.emit('lcSuspend', this.mainWindow.id); this.suspended = true; this.windowList[this.windowList.length - 1].hide(); this.flushData(); - if (!this.backgroundRunnable() || this.inQuit) { + if (!this.backgroundRunnable()) { if (!this.multitaskingSupport) { // FIXME : terminate app after visibilitychange event handling setTimeout(() => { @@ -383,6 +383,9 @@ Then you can get profile log from the initial loading.`; console.log('WebApplication : finalize'); this.flushData(); this.windowList.forEach((window) => window.removeAllListeners()); + this.inQuit = false; + if (!this.suspended) + this.suspend(); } quit() { @@ -398,8 +401,6 @@ Then you can get profile log from the initial loading.`; wrt.stopInspectorServer(); } this.inQuit = true; - if (!this.suspended) - this.suspend(); } private flushData() { -- 2.7.4 From 45bec9aac1c754eaa7ffbe120b322972e9d754b5 Mon Sep 17 00:00:00 2001 From: jihwankim Date: Wed, 28 Oct 2020 13:10:22 +0900 Subject: [PATCH 13/16] [DA] Show native window in app-control. Now, native window is shown when 'ready-to-show' is called. This is an intentional operation using an electron api. But because of this, there is a VOC that the launch speed of the web app seems to be slow. DA decided that it would be better to show the window if it is not ready. (Even if it is an empty screen) So call WebApplication.show in app-control callback. This patch uses DAExtension api, so this should be applied with or after the patch below. https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/246305/ Change-Id: I5a872ab0408b739d86890fc03c942c927160fdc8 Signed-off-by: jihwankim --- wrt_app/src/runtime.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrt_app/src/runtime.ts b/wrt_app/src/runtime.ts index 0f81a53..928d595 100644 --- a/wrt_app/src/runtime.ts +++ b/wrt_app/src/runtime.ts @@ -114,6 +114,9 @@ class Runtime { } this.webApplication.mainWindow.loadURL(src); this.webApplication.prelaunch(src); + if (wrt.da) { + this.webApplication.show(); + } } else { console.log('Handling app-control event'); if (this.webApplication.preloadStatus == 'readyToShow') { -- 2.7.4 From 719e2eed6fa5e882b6075d56f78c4e1a6330d378 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 29 Oct 2020 16:10:52 +0900 Subject: [PATCH 14/16] [Service] Release fake timer when stopService. This fake timer is to avoid unknown uv loop delay issue. It should clear this fake timer after stopService. Change-Id: I320dcdf6d0b0066e560692bdb9c56b3ec9b8352a Signed-off-by: DongHyun Song --- wrt_app/common/service_runner.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index c3c8306..a869101 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -39,6 +39,8 @@ function requestStopService(id: string) { } let app: any = null; +let fakeTimer: any; + export function start(id: string, filename: string) { XWalkExtension.initialize(); XWalkExtension.setRuntimeMessageHandler((type, data) => { @@ -59,7 +61,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 - setInterval(() => {}, 100); + fakeTimer = setInterval(() => {}, 100); try { app = require(filename); if (app.onStart !== undefined) { @@ -78,6 +80,8 @@ export function start(id: string, filename: string) { } export function stop(id: string) { + if (fakeTimer) + clearInterval(fakeTimer); try { if (app.onStop !== undefined) { app.onStop(); -- 2.7.4 From f93dfc53d1b8626d3204c41113d86497b90f7ad3 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 2 Nov 2020 16:55:24 +0900 Subject: [PATCH 15/16] [Service] Refactor unload xwalk extension unloadInstance() is introduced for optimizing memory on global model. But with irregular crash problems on UvTaskRunner's OnTimeout function, it try to access xwalk instance after deleted. This patch will remove calling unloadInstance() API. Unloading xwalk extension will be refactored below patch. Related patch: https://review.tizen.org/gerrit/246586/ Change-Id: Ie6a74b815680f02530fd2553427d03bf1634d612 Signed-off-by: DongHyun Song --- wrt_app/common/wrt_xwalk_extension.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/wrt_app/common/wrt_xwalk_extension.ts b/wrt_app/common/wrt_xwalk_extension.ts index f7ba13d..23106e6 100644 --- a/wrt_app/common/wrt_xwalk_extension.ts +++ b/wrt_app/common/wrt_xwalk_extension.ts @@ -220,9 +220,6 @@ export const setRuntimeMessageHandler = (handler: (type: string, data?: string, } export let cleanup = () => { - for (var name in extensions_) { - extensions_[name].unloadInstance(); - } delete global.tizen; instance = undefined; } -- 2.7.4 From 480b6888ff5a0e9fd5983788fc4a98d97e32e217 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Fri, 6 Nov 2020 09:48:12 +0900 Subject: [PATCH 16/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 --- 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 a869101..2624f12 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -106,7 +106,7 @@ function run() { stop(id); setTimeout(() => { XWalkExtension.cleanup(); - process.exit() + parentPort?.postMessage("will-terminate"); }, message.delay); } }); -- 2.7.4