From a5bef9bb9dcb1b1d997a5098782cbee09e55eb10 Mon Sep 17 00:00:00 2001 From: Youngsoo Choi Date: Mon, 7 Sep 2020 04:53:21 -0700 Subject: [PATCH 01/16] fixup! [D2D] Support wgt-in-rpm for d2d server This moves libtzplatform-config for all profiles. Change-Id: I82c17747678ae0dc2afa662c6ea5834f4fd597d8 Signed-off-by: Youngsoo Choi --- packaging/wrtjs.spec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/wrtjs.spec b/packaging/wrtjs.spec index 2d0621b..69093e1 100755 --- a/packaging/wrtjs.spec +++ b/packaging/wrtjs.spec @@ -31,8 +31,8 @@ BuildRequires: pkgconfig(dlog) BuildRequires: app-signer %endif BuildRequires: hash-signer, zip -BuildRequires: pkgconfig(libtzplatform-config) %endif +BuildRequires: pkgconfig(libtzplatform-config) %description Web Runtime Engine based on Electron @@ -177,9 +177,9 @@ cp -r %{app_dir}/* %{buildroot}%{_resourcedir}/ %endif %if 0%{?_use_d2d} - install -d %{buildroot}%{_xmldir} - install -d %{buildroot}%{_appdir}/%{_d2d_pkgid}/res install -d %{buildroot}%{_appdir}/%{_d2d_pkgid}/bin + install -d %{buildroot}%{_appdir}/%{_d2d_pkgid}/res + install -d %{buildroot}%{_xmldir} install -m 0644 packaging/%{_d2d_pkgid}.xml %{buildroot}%{_xmldir}/ cp -rf d2d_app %{buildroot}%{_appdir}/%{_d2d_pkgid}/res/wgt/ ln -sf %{_bindir}/wrt-service-launcher %{buildroot}%{_appdir}/%{_d2d_pkgid}/bin/%{_d2d_pkgid}.Service @@ -232,8 +232,8 @@ rm -fr %{buildroot} %manifest packaging/wrtjs.manifest %license LICENSE %if 0%{?_use_d2d} - %{_xmldir}/%{_d2d_pkgid}.xml %{_appdir}/%{_d2d_pkgid} + %{_xmldir}/%{_d2d_pkgid}.xml %endif %if "%{?tizen_profile_name}" != "tv" %caps(cap_setgid,cap_sys_admin=ei) %{_bindir}/wrt-loader -- 2.7.4 From 5f2026e23c25a9da850c1ec0c506eaa612ee7c8e Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 2 Sep 2020 17:16:19 +0900 Subject: [PATCH 02/16] [Service] Introduce worker isolation node-vm, previous way to isolate service applications, has a big problem of global scope sharing with Tizen webapis. Becuase tizen webapi objects are registered on global scope, with DeviceAPIRouter overrieded APIs are shared by each service application calling. In addition, require() is also running on global scope, even though apps are calling require() in their sandbox context, imported modules are running global scope. Thus, isolation of global scope is most important for global wrt- service. Node worker is very proper way to isolate each service application. With node worker, v8::Isolatee and v8::IsolateData are created separately. Then, each service app is able to have each independent global object. Reference patch: https://review.tizen.org/230796/ Change-Id: Ic4008ed7a8331327eeb84facba55418e971e2271 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 166 +++++------------------------- wrt_app/common/service_runner.ts | 103 ++++++++++++++++++ wrt_app/service/access_control_manager.ts | 5 +- wrt_app/service/device_api_router.ts | 110 ++++++++++++++------ wrt_app/service/main.ts | 2 +- 5 files changed, 209 insertions(+), 177 deletions(-) create mode 100644 wrt_app/common/service_runner.ts diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 330e441..80f1ec6 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -1,157 +1,37 @@ -const Module = require('module'); -import { TimerManager } from '../service/timer_manager'; -import * as XWalkExtension from './wrt_xwalk_extension'; -import * as vm from 'vm'; +import { Worker, isMainThread } from 'worker_threads'; import { wrt } from '../browser/wrt'; -import { DeviceAPIRouter } from '../service/device_api_router'; -interface ContextMap { - [id: string]: vm.Context; +interface WorkerMap { + [id: string]: any; } +let workers: WorkerMap = {}; +let serviceType: string = wrt.getServiceModel();; +let runner: any; -interface ContextOption { - [key: string]: any; +function isStandalone() { + return serviceType === 'STANDALONE'; } -let sandbox: ContextMap = {}; -let internal_handler: ContextOption = {}; -let service_type: string = wrt.getServiceModel?.() ?? 'UI'; - -function requestStopService(id: string) { - console.log(`${id} will be closed`); - setTimeout(() => wrt.stopService(id), 500); -} - -function callFunctionInContext(name: string, id: string) { - try { - const script = `if (typeof ${name} === 'function') { ${name}(); }`; - vm.runInContext(script, sandbox[id]); - } catch (e) { - console.log(`${name} has exception: ${e}`); - if (wrt.tv) { - requestStopService(id); +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'; + workers[id] = new Worker(startService, { workerData: { id: id, filename: filename } }); } } } -export function startService(id: string, filename?: string) { - if (sandbox[id] === undefined) { - XWalkExtension.initialize(); - XWalkExtension.setRuntimeMessageHandler((type, data) => { - if (type === 'tizen://exit') { - requestStopService(id); - } - }); - sandbox[id] = { - console: console, - module: new Module, - require: require, - tizen: global.tizen, - webapis: wrt.tv ? global.webapis : global.webapis = {}, - }; - sandbox[id].module.exports.onStop = () => { - callFunctionInContext('module.exports.onExit', id); - }; - let ids = id.split(':'); - let caller_app_id = ids[1] ?? ''; - sandbox[id].webapis.getCallerAppId = () => { - return caller_app_id; - } - let service_id = ids[0]; - sandbox[id].webapis.getServiceId = () => { - return service_id; - } - sandbox[id].webapis.getPackageId = () => { - let app_info = global.tizen.application.getAppInfo(service_id); - if (app_info) - return app_info.packageId; - return ids[0].split('.')[0]; - } - - if (service_type !== 'UI') { - const permissions = wrt.getPrivileges(id); - console.log(`permissions : ${permissions}`); - const AccessControlManager = require('../service/access_control_manager'); - AccessControlManager.initialize(permissions, sandbox[id]); - } - for (let key in global) - sandbox[id][key] = global[key]; - - internal_handler[id] = {}; - internal_handler[id].timer_manager = new TimerManager(); - const timer_api = internal_handler[id].timer_manager.getTimerAPI(); - for (let key in timer_api) - sandbox[id][key] = timer_api[key]; - - let object_list = [ 'Error', 'EvalError', 'RangeError', 'ReferenceError', - 'SyntaxError', 'TypeError', 'URIError', 'Number', 'BigInt', 'Math', 'Date', - 'String', 'RegExp', 'Array', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', - 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', - 'Float64Array', 'BigInt64Array', 'BigUint64Array', 'Map', 'Set', 'WeakMap', - 'WeakSet', 'ArrayBuffer', 'DataView', 'JSON', 'Promise', 'Reflect', 'Proxy', - 'Intl', 'WebAssembly', 'Boolean', 'Function', 'Object', 'Symbol' ]; - for (let prop of object_list) - sandbox[id][prop] = global[prop]; - - let options: ContextOption = {}; - let code; - if (service_type !== 'UI') { - options.filename = id; - if (wrt.tv) { - let extension_resolver = function (module: any, file_path: string) { - console.log(`resolved path: ${file_path}`); - let content = (wrt.tv as NativeWRTjs.TVExtension).decryptFile(id, file_path); - if (content) { - // Remove BOM - if (content.charCodeAt(0) === 0xFEFF) - content = content.slice(1); - module._compile(content, file_path); - } - }; - sandbox[id].require.extensions['.js.spm'] = extension_resolver; - sandbox[id].require.extensions['.spm'] = extension_resolver; - } - filename = wrt.getStartServiceFile(id); - console.log(`start global service file: ${filename}`); - } - code = `const app = require('${filename}')`; - if (service_type === 'DAEMON') { - internal_handler[id].deivce_api_router = new DeviceAPIRouter(sandbox[id]); +export function stopService(id: string) { + console.log(`stopService - ${id}`); + if (isStandalone()) { + if (runner) { + runner.stop(id); } - vm.runInNewContext(code, sandbox[id], options); - } - - if (sandbox[id]['started'] === undefined) { - sandbox[id]['started'] = true; - sandbox[id]['stopped'] = undefined; - callFunctionInContext('app.onStart', id); - if (service_type !== 'UI') - wrt.finishStartingService(id); } else { - console.log(id + ' service has been started.'); + workers[id].postMessage('stopService'); } - callFunctionInContext('app.onRequest', id); -} - -export function stopService(id: string) { - console.log('stopService') - if (sandbox[id]['stopped']) { - console.log(id + ' service has been already stopped.'); - return; - } - - sandbox[id]['stopped'] = true; - sandbox[id]['started'] = undefined; - callFunctionInContext('app.onStop', id); - - internal_handler[id].timer_manager.releaseRemainingTimers(); - for (let key in sandbox[id]) - delete sandbox[id][key]; - delete sandbox[id]; - for (let key in internal_handler[id]) - delete internal_handler[id][key]; - delete internal_handler[id]; - - if (Object.keys(sandbox).length === 0) - XWalkExtension.cleanup(); } diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts new file mode 100644 index 0000000..7b53192 --- /dev/null +++ b/wrt_app/common/service_runner.ts @@ -0,0 +1,103 @@ +import './init'; +import * as XWalkExtension from './wrt_xwalk_extension'; +import { DeviceAPIRouter } from '../service/device_api_router'; +import { isMainThread, parentPort, workerData } from 'worker_threads'; +import { wrt } from '../browser/wrt'; + +let serviceType: string = wrt.getServiceModel(); + +function isServiceApplication() { + return serviceType !== 'UI'; +} + +function isGloablService() { + return serviceType === 'DAEMON'; +} + +function registerExtensionResolver(id: string) { + if (wrt.tv) { + let extensionResolver = (module: any, file_path: string) => { + console.log(`resolved path: ${file_path}`); + let content = (wrt.tv as NativeWRTjs.TVExtension).decryptFile(id, file_path); + if (content) { + // Remove BOM + if (content.charCodeAt(0) === 0xFEFF) + content = content.slice(1); + module._compile(content, file_path); + } + }; + require.extensions['.js.spm'] = extensionResolver; + require.extensions['.spm'] = extensionResolver; + } +} + +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); + } + }); + + console.log('serviceType : '+serviceType) + new DeviceAPIRouter(id, isGloablService()); + + if (isServiceApplication()) { + registerExtensionResolver(id); + filename = wrt.getStartServiceFile(id); + console.log(`start global service file: ${filename}`); + } + + // FIXME: this is for awaking up uv loop. + // uv loop is sleeping for a few second with tizen webapis's aync callback + setInterval(() => {}, 100); + try { + app = require(filename); + if (app.onStart !== undefined) { + app.onStart(); + } + if (app.onRequest !== undefined) { + app.onRequest(); + } + if (isGloablService()) { + wrt.finishStartingService(id); + } + } catch (e) { + console.log(`exception on start: ${e}`); + setTimeout(() => wrt.stopService(id), 500); + } +} + +export function stop(id: string) { + try { + if (app.onStop !== undefined) { + app.onStop(); + } else if (app.onExit !== undefined) { + app.onExit(); + } + } catch (e) { + console.log(`exception on stop: ${e}`); + } + setTimeout(() => process.exit(), 500); +} + +function run() { + let id = workerData.id; + let filename = workerData.filename; + start(id, filename); + + if (!parentPort) + return; + parentPort.on('message', (msg) => { + console.log(`message received : ${msg}`); + if (msg === 'stopService') { + stop(id); + } + }); +} + +if (!isMainThread) { + run(); +} diff --git a/wrt_app/service/access_control_manager.ts b/wrt_app/service/access_control_manager.ts index 0a00ac5..120fe1c 100644 --- a/wrt_app/service/access_control_manager.ts +++ b/wrt_app/service/access_control_manager.ts @@ -1,4 +1,3 @@ -import * as vm from 'vm'; function checkSystemInfoApiPrivilege(func: any, permissions: string[]) { let override_func = func; @@ -11,8 +10,8 @@ function checkSystemInfoApiPrivilege(func: any, permissions: string[]) { } } -export function initialize(permissions: string[], sandbox: vm.Context) { - let tizen = sandbox.tizen; +export function initialize(permissions: string[]) { + let tizen = global.tizen; if (!permissions.includes("http://tizen.org/privilege/alarm")) { tizen.alarm.add = tizen.alarm.remove = diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index a64c549..b7f645b 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -2,7 +2,6 @@ import { wrt } from '../browser/wrt'; export class DeviceAPIRouter { currentApplication: any; - sandbox: any; funcCurrentApplication: any; funcRequestedAppcontrol: any; funcGetAppInfo: any; @@ -10,37 +9,75 @@ export class DeviceAPIRouter { funcGetSharedUri: any; funcGetMetadata: any; funcGetPackageInfo: any; - funcPathResolve: any; - constructor(sandbox: any) { - this.sandbox = sandbox; - this.RefineApplicationApis(); - this.RefinePackageApis(); - this.RefineFilesystemApis() + id: string; + serviceId: string; + packageId: string; + callerAppId: string; + + constructor(id: string, isGlobal: boolean) { + this.id = id; + let ids = id.split(':'); + this.serviceId = ids[0]; + this.callerAppId = ids[1] ?? ''; + this.packageId = this.serviceId.split('.')[0]; + + this.initWebapis(); + if (isGlobal) { + this.refineApplicationApis(); + this.refinePackageApis(); + this.refineFilesystemApis() + this.initAccessControlManager(); + } + } + + initWebapis() { + global.webapis = global.webapis ?? {}; + + global.webapis.getCallerAppId = () => { + return this.callerAppId; + } + global.webapis.getServiceId = () => { + return this.serviceId; + } + let app_info = global.tizen.application.getAppInfo(this.serviceId); + if (app_info) { + this.packageId = app_info.packageId; + } + global.webapis.getPackageId = () => { + return this.packageId; + } } - GetServiceId() { - return this.sandbox.webapis.getServiceId(); + initAccessControlManager() { + const permissions = wrt.getPrivileges(this.id); + console.log(`permissions : ${permissions}`); + const AccessControlManager = require('./access_control_manager'); + AccessControlManager.initialize(permissions); } - GetPackageId() { - return this.sandbox.webapis.getPackageId(); + getServiceId() { + return global.webapis.getServiceId(); } - RefineApplicationApis() { + getPackageId() { + return global.webapis.getPackageId(); + } + + refineApplicationApis() { // tizen.application.getCurrentApplication() this.funcCurrentApplication = global.tizen.application.getCurrentApplication; global.tizen.application.getCurrentApplication = () => { - console.log(`Routing - getCurrentApplication() : ${this.GetServiceId()}`); + console.log(`Routing - getCurrentApplication() : ${this.getServiceId()}`); if (this.currentApplication) return this.currentApplication; this.currentApplication = this.funcCurrentApplication(); // tizen.application.getCurrentApplication().getRequestedAppControl() this.funcRequestedAppcontrol = this.currentApplication.getRequestedAppControl; this.currentApplication.getRequestedAppControl = () => { - console.log(`Routing - getRequestedAppControl() : ${this.GetServiceId()}`); + console.log(`Routing - getRequestedAppControl() : ${this.getServiceId()}`); if (wrt.tv) - wrt.tv.setCurrentApplication(this.GetServiceId()); + wrt.tv.setCurrentApplication(this.getServiceId()); return this.funcRequestedAppcontrol(); } return this.currentApplication; @@ -50,7 +87,7 @@ export class DeviceAPIRouter { global.tizen.application.getAppInfo = (app_id?: string) => { console.log(`Routing - getAppInfo()`); if (!app_id) - app_id = this.GetServiceId(); + app_id = this.getServiceId(); return this.funcGetAppInfo(app_id); } // tizen.application.getAppCerts() @@ -58,7 +95,7 @@ export class DeviceAPIRouter { global.tizen.application.getAppCerts = (app_id?: string) => { console.log(`Routing - getAppCerts()`); if (!app_id) - app_id = this.GetServiceId(); + app_id = this.getServiceId(); return this.funcGetAppcerts(app_id); } // tizen.application.getAppSharedURI() @@ -66,7 +103,7 @@ export class DeviceAPIRouter { global.tizen.application.getAppSharedURI = (app_id?: string) => { console.log(`Routing - getAppSharedURI()`); if (!app_id) - app_id = this.GetServiceId(); + app_id = this.getServiceId(); return this.funcGetSharedUri(app_id); } // tizen.application.getAppMetaData() @@ -74,31 +111,44 @@ export class DeviceAPIRouter { global.tizen.application.getAppMetaData = (app_id?: string) => { console.log(`Routing - getAppMetaData()`); if (!app_id) - app_id = this.GetServiceId(); + app_id = this.getServiceId(); return this.funcGetMetadata(app_id); } } - RefinePackageApis() { + refinePackageApis() { // tizen.package.getPackageInfo() this.funcGetPackageInfo = global.tizen.package.getPackageInfo; global.tizen.package.getPackageInfo = (package_id?: string) => { console.log(`Routing - getPackageInfo()`); if (!package_id) - package_id = this.GetPackageId(); + package_id = this.getPackageId(); return this.funcGetPackageInfo(package_id); } } - RefineFilesystemApis() { - // tizen.filesystem.resolve - this.funcPathResolve = global.tizen.filesystem.resolve; - global.tizen.filesystem.resolve = (location: string, onSuccess: Function, - onError?: Function, mode?: string) => { - console.log(`Routing - resolve(${location})`); - let service_id = this.GetServiceId(); - location = wrt.resolveVirtualRoot(service_id, location); - this.funcPathResolve(location, onSuccess, onError, mode ?? 'rw'); + injectVirtualRootResolver(func: Function) { + return (...args: any[]) => { + console.log(args); + args[0] = wrt.resolveVirtualRoot(this.getServiceId(), args[0]); + console.log(args[0]); + func.apply(global.tizen.filesystem, args); } } + + refineFilesystemApis() { + 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); + global.tizen.filesystem.moveFile = this.injectVirtualRootResolver(global.tizen.filesystem.moveFile); + global.tizen.filesystem.copyFile = this.injectVirtualRootResolver(global.tizen.filesystem.copyFile); + global.tizen.filesystem.isFile = this.injectVirtualRootResolver(global.tizen.filesystem.isFile); + global.tizen.filesystem.toURI = this.injectVirtualRootResolver(global.tizen.filesystem.toURI); + global.tizen.filesystem.isDirectory = this.injectVirtualRootResolver(global.tizen.filesystem.isDirectory); + global.tizen.filesystem.pathExists = this.injectVirtualRootResolver(global.tizen.filesystem.pathExists); + } } diff --git a/wrt_app/service/main.ts b/wrt_app/service/main.ts index 3aa42ee..6fa2f41 100755 --- a/wrt_app/service/main.ts +++ b/wrt_app/service/main.ts @@ -23,7 +23,7 @@ import * as BuiltinService from './builtins/builtin_handler'; wrt.on('start-service', (event: any, internal_id: string) => { console.log('start service app : ' + internal_id); - ServiceManager.startService(internal_id); + ServiceManager.startService(internal_id, ''); }); wrt.on('stop-service', (event: any, internal_id: string) => { -- 2.7.4 From d4c464b2233281728d03ad3cb22ba7daedd283cc Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 2 Sep 2020 17:16:19 +0900 Subject: [PATCH 03/16] [Service] Fix memory leak with worker isolation 1) apply worker.terminate(), instead of process.exit() 2) unload extensions to release extensions Related chromium-efl patch: https://review.tizen.org/gerrit/243536 Change-Id: I575fa68d72280d542e36add0d5d7f4f27adb98bc Signed-off-by: DongHyun Song --- packaging/wrtjs.spec | 2 +- wrt_app/common/service_manager.ts | 13 ++++++++++--- wrt_app/common/service_runner.ts | 2 +- wrt_app/common/wrt_xwalk_extension.ts | 3 +++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packaging/wrtjs.spec b/packaging/wrtjs.spec index 69093e1..842226c 100755 --- a/packaging/wrtjs.spec +++ b/packaging/wrtjs.spec @@ -2,7 +2,7 @@ Name: wrtjs Summary: Javascript based Runtime for Tizen # Version: {TPK_VERSION}.{INTERNAL_API_REVISION}.{WRTJS_VERSION} # The {INTERNAL_API_REVISION} is used to check compatibility with chromium-efl. -Version: 1.0.1 +Version: 1.1.1 Release: 1 Group: Web Framework/Web Runtime License: Apache-2.0 diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 80f1ec6..6703ff4 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -28,10 +28,17 @@ export function startService(id: string, filename: string) { export function stopService(id: string) { console.log(`stopService - ${id}`); if (isStandalone()) { - if (runner) { - runner.stop(id); + if (!runner) { + console.log('runner instance is null in standalone mode'); + return; } - } else { + runner.stop(id); + setTimeout(() => process.exit(), 500); +} else { workers[id].postMessage('stopService'); + setTimeout(() => { + workers[id].terminate(); + delete workers[id]; + }, 500); } } diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index 7b53192..8e1c032 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -80,7 +80,6 @@ export function stop(id: string) { } catch (e) { console.log(`exception on stop: ${e}`); } - setTimeout(() => process.exit(), 500); } function run() { @@ -94,6 +93,7 @@ function run() { console.log(`message received : ${msg}`); if (msg === 'stopService') { stop(id); + XWalkExtension.cleanup(); } }); } diff --git a/wrt_app/common/wrt_xwalk_extension.ts b/wrt_app/common/wrt_xwalk_extension.ts index ea8ad96..feffcdd 100644 --- a/wrt_app/common/wrt_xwalk_extension.ts +++ b/wrt_app/common/wrt_xwalk_extension.ts @@ -214,6 +214,9 @@ 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 6f0e9a8166b86205c77bb5c22b2dd8ea4df21642 Mon Sep 17 00:00:00 2001 From: Aron kim Date: Wed, 9 Sep 2020 22:16:15 -0700 Subject: [PATCH 04/16] [D2D] Modify to not launch d2d app repeatedly. When the remote client launching the d2d app in device home, change to connect only the websocket if the d2d app status is visible. Change-Id: Iab323ee86cc3a979521daf6c3a6b7485904233a6 Signed-off-by: Aron kim --- d2d_app/service/app_proxy.js | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/d2d_app/service/app_proxy.js b/d2d_app/service/app_proxy.js index 7255840..3db4507 100644 --- a/d2d_app/service/app_proxy.js +++ b/d2d_app/service/app_proxy.js @@ -2,6 +2,7 @@ var express = require('express'); const AppRouter = require('./app_router'); var appRouters = []; var path = null; +var currentD2DAppId = null; module.exports = function(app, port) { var appProxy = express.Router(); @@ -27,16 +28,34 @@ module.exports = function(app, port) { }); } - var appControl = new tizen.ApplicationControl( - "http://tizen.org/appcontrol/operation/default", null, null, null, - [new tizen.ApplicationControlData( - "http://tizen.org/appcontrol/data/launch_port", [port] - )] - ); + function onRunningAppsContext(contexts) { + var isRunning = false; + for (var i = 0; i < contexts.length; i++) { + if (appId === contexts[i].appId) { + isRunning = true; + break; + } + } + + if (isRunning && currentD2DAppId === appId) { + res.send({port:port}); + } else { + var appControl = new tizen.ApplicationControl( + "http://tizen.org/appcontrol/operation/default", null, null, null, + [new tizen.ApplicationControlData( + "http://tizen.org/appcontrol/data/launch_port", [port] + )] + ); + + tizen.application.launchAppControl(appControl, appId, function() { + res.send({port:port}); + }); + + currentD2DAppId = appId; + } + } - tizen.application.launchAppControl(appControl, appId, function() { - res.send({port:port}); - }); + tizen.application.getAppsContext(onRunningAppsContext); }); appProxy.get('/', (req, res) => { -- 2.7.4 From a7074bcb103eefddf99c5ee94e52a661db318c37 Mon Sep 17 00:00:00 2001 From: Youngsoo Choi Date: Thu, 10 Sep 2020 18:38:21 -0700 Subject: [PATCH 05/16] [Service] Call global.gc() when terminating a service This calls global.gc() when a service app is terminated. Approximately, 1 MB memory is saved by this. Also, the main thread is immediately terminated when there's no running worker thread for service app. Together with: https://review.tizen.org/gerrit/243858 Change-Id: Iab70e9aadedb19295a3784fb5cc3dc1300412995 Signed-off-by: Youngsoo Choi --- wrt_app/common/service_manager.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 6703ff4..9637542 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -21,6 +21,14 @@ export function startService(id: string, filename: string) { if (isMainThread) { let startService = __dirname + '/service_runner.js'; workers[id] = new Worker(startService, { workerData: { id: id, filename: filename } }); + workers[id].on('exit', () => { + try { + global.gc(); + console.log(`global.gc() is called by ${id}`); + } catch (e) { + console.log(`${e.name}: ${e.message}`); + } + }); } } } @@ -34,11 +42,16 @@ export function stopService(id: string) { } runner.stop(id); setTimeout(() => process.exit(), 500); -} else { + } else { workers[id].postMessage('stopService'); setTimeout(() => { workers[id].terminate(); delete workers[id]; + let runningServices = Object.keys(workers).length; + console.log('Running services : ' + runningServices); + if (runningServices === 0 && serviceType !== 'UI') { + process.exit(); + } }, 500); } } -- 2.7.4 From cb6609d8d332a8cc7ab20bd772b56c02362a64f4 Mon Sep 17 00:00:00 2001 From: Chunling Ye Date: Tue, 4 Aug 2020 15:41:28 +0800 Subject: [PATCH 06/16] [Service]Add more xwalk extensions for service app 1.add xwalk extensions: exif/content/download/account/iotcon 2.fix window not defined error for exif extension Change-Id: I5c53c8d4bbc0fc0267e05c14b50731f628024732 Signed-off-by: Chunling Ye --- packaging/plugins.json | 26 ++++++++++++++++++++++++++ wrt_app/common/wrt_xwalk_extension.ts | 1 + 2 files changed, 27 insertions(+) diff --git a/packaging/plugins.json b/packaging/plugins.json index ba82e28..26d4f0a 100644 --- a/packaging/plugins.json +++ b/packaging/plugins.json @@ -48,5 +48,31 @@ "name":"tizen.alarm", "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_alarm.so", "entry_points": ["tizen.AlarmRelative","tizen.AlarmAbsolute"] + }, + { + "name":"tizen.exif", + "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_exif.so", + "entry_points": ["tizen.ExifInformation"] + }, + { + "name":"tizen.content", + "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_content.so", + "entry_points": [] + }, + { + "name":"tizen.download", + "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_download.so", + "entry_points": ["tizen.DownloadRequest"] + }, + { + "name":"tizen.account", + "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_account.so", + "entry_points": ["tizen.Account"] + }, + { + "name":"tizen.iotcon", + "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_iotcon.so", + "entry_points": ["tizen.IotconOption","tizen.Query","tizen.QueryFilter", + "tizen.Representation","tizen.Response","tizen.State"] } ] diff --git a/wrt_app/common/wrt_xwalk_extension.ts b/wrt_app/common/wrt_xwalk_extension.ts index feffcdd..461e7dd 100644 --- a/wrt_app/common/wrt_xwalk_extension.ts +++ b/wrt_app/common/wrt_xwalk_extension.ts @@ -23,6 +23,7 @@ interface NativeXWalkExtension extends NativeWRTjs.XWalkExtension { let instance: XWalkExtension | undefined; let api_: { [key: string]: any } = {}; let extensions_: { [key: string]: NativeXWalkExtension } = {}; +global.window = global.window ?? global; class XWalkExtension { constructor() { -- 2.7.4 From 275f022e89171ece776f80e104eb8a3767240fde Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 17 Sep 2020 16:52:51 +0900 Subject: [PATCH 07/16] [Service] Remove global.gc() LowMemoryNotification() with repeat timer will replace global.gc() in JavascriptEnvironment side. Related chromium-efl patch: https://review.tizen.org/gerrit/244329 Change-Id: I18864ed3de3b3c7ac367f4d247e3e1b81a9c9564 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 9637542..ea6e1df 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -21,14 +21,6 @@ export function startService(id: string, filename: string) { if (isMainThread) { let startService = __dirname + '/service_runner.js'; workers[id] = new Worker(startService, { workerData: { id: id, filename: filename } }); - workers[id].on('exit', () => { - try { - global.gc(); - console.log(`global.gc() is called by ${id}`); - } catch (e) { - console.log(`${e.name}: ${e.message}`); - } - }); } } } -- 2.7.4 From 569ecd5822a96e855bb0df54733a63830568b4fb Mon Sep 17 00:00:00 2001 From: "k2.nagaraju" Date: Wed, 16 Sep 2020 23:16:01 +0530 Subject: [PATCH 08/16] [Service] update package_id based on input received If passed parameter is |false| or |undefined| then also |package_id| is updated as current package. which is causing failure in package service webtct failure. Change-Id: I6823ed175c3e65224e699d3084b28cd27eb3fab9 Signed-off-by: k2.nagaraju --- wrt_app/service/device_api_router.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index b7f645b..3772d5d 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -119,10 +119,11 @@ export class DeviceAPIRouter { refinePackageApis() { // tizen.package.getPackageInfo() this.funcGetPackageInfo = global.tizen.package.getPackageInfo; - global.tizen.package.getPackageInfo = (package_id?: string) => { - console.log(`Routing - getPackageInfo()`); - if (!package_id) + global.tizen.package.getPackageInfo = (...args: any[]) => { + let package_id = args[0]; + if (!args.length || args[0] === null) package_id = this.getPackageId(); + console.log(`Routing - getPackageInfo() : ${package_id}`); return this.funcGetPackageInfo(package_id); } } -- 2.7.4 From 6b7c4aab36e0ebbe3e5bffb27867d39239532e99 Mon Sep 17 00:00:00 2001 From: "k2.nagaraju" Date: Tue, 22 Sep 2020 00:02:04 +0530 Subject: [PATCH 09/16] [service] filesystem web deviceapi call getting hanged. filesystem deviceapi calls are overloaded, some functions expecting return value. But it is not returning, which is causing failure of test cases. Change-Id: I77d08193fcc9aa7505f53836a36b78cb82697b30 Signed-off-by: k2.nagaraju --- wrt_app/service/device_api_router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index 3772d5d..5d65aa3 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -133,7 +133,7 @@ export class DeviceAPIRouter { console.log(args); args[0] = wrt.resolveVirtualRoot(this.getServiceId(), args[0]); console.log(args[0]); - func.apply(global.tizen.filesystem, args); + return func.apply(global.tizen.filesystem, args); } } -- 2.7.4 From 3985daa08f8f8373cebdcdbc1aa843bf6059e30c Mon Sep 17 00:00:00 2001 From: Aron kim Date: Tue, 22 Sep 2020 23:02:17 -0700 Subject: [PATCH 10/16] [D2D] Add privilege for DeviceWebServer. http://tizen.org/privilege/filesystem.read http://tizen.org/privilege/filesystem.write http://tizen.org/privilege/mediastorage Change-Id: I393428a9a6d44ecd6311e425a4d3fe6f76bec29f Signed-off-by: Aron kim --- d2d_app/config.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/d2d_app/config.xml b/d2d_app/config.xml index f84c871..3f3ecfc 100755 --- a/d2d_app/config.xml +++ b/d2d_app/config.xml @@ -7,6 +7,9 @@ + + + -- 2.7.4 From c5297c3540f1761d8fa4caad0413efac64e4a765 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 14 Sep 2020 19:02:37 +0900 Subject: [PATCH 11/16] [Service] Refactor builtin-service with node worker This applies builtin-service to execute on node worker same as service application with refactoring worker creation/termination. Change-Id: I105a4e3f91409deb9805ac2ca08e4e62a162c2fa Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 68 +++++++++++++++++++++++------ wrt_app/common/service_runner.ts | 6 +-- wrt_app/service/builtins/builtin_handler.ts | 30 ------------- wrt_app/service/builtins/wasm_builder.ts | 11 ++--- wrt_app/service/main.ts | 5 +-- 5 files changed, 66 insertions(+), 54 deletions(-) delete mode 100644 wrt_app/service/builtins/builtin_handler.ts diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index ea6e1df..b9daf4e 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -5,13 +5,48 @@ interface WorkerMap { [id: string]: any; } let workers: WorkerMap = {}; -let serviceType: string = wrt.getServiceModel();; +let serviceType: string = wrt.getServiceModel(); let runner: any; +function isGlobalService() { + return serviceType === 'DAEMON'; +} + function isStandalone() { return serviceType === 'STANDALONE'; } +function createWorker(id: string, startService: string, filename: string) { + if (workers[id]) { + console.log(`This worker is already running. ${id}`); + return; + } + workers[id] = new Worker(startService, { + workerData: { + id, + filename + } + }); +} + +function terminateWorker(id: string, delay: number) { + if (!workers[id]) { + 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); +} + export function startService(id: string, filename: string) { console.log(`startService - ${id}`); if (isStandalone()) { @@ -19,8 +54,8 @@ export function startService(id: string, filename: string) { runner.start(id, filename); } else { if (isMainThread) { - let startService = __dirname + '/service_runner.js'; - workers[id] = new Worker(startService, { workerData: { id: id, filename: filename } }); + let startService = `${__dirname}/service_runner.js`; + createWorker(id, startService, filename); } } } @@ -35,15 +70,22 @@ export function stopService(id: string) { runner.stop(id); setTimeout(() => process.exit(), 500); } else { - workers[id].postMessage('stopService'); - setTimeout(() => { - workers[id].terminate(); - delete workers[id]; - let runningServices = Object.keys(workers).length; - console.log('Running services : ' + runningServices); - if (runningServices === 0 && serviceType !== 'UI') { - process.exit(); - } - }, 500); + terminateWorker(id, 500); } } + +export function handleBuiltinService(serviceId: string, serviceName: string) { + if (!serviceName) { + return; + } + let need_stop = (serviceName.substr(0, 5) === 'stop_'); + if (need_stop) { + terminateWorker(serviceId, 0); + } else { + if (isMainThread) { + 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 8e1c032..7ea5bca 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -10,7 +10,7 @@ function isServiceApplication() { return serviceType !== 'UI'; } -function isGloablService() { +function isGlobalService() { return serviceType === 'DAEMON'; } @@ -42,7 +42,7 @@ export function start(id: string, filename: string) { }); console.log('serviceType : '+serviceType) - new DeviceAPIRouter(id, isGloablService()); + new DeviceAPIRouter(id, isGlobalService()); if (isServiceApplication()) { registerExtensionResolver(id); @@ -61,7 +61,7 @@ export function start(id: string, filename: string) { if (app.onRequest !== undefined) { app.onRequest(); } - if (isGloablService()) { + if (isGlobalService()) { wrt.finishStartingService(id); } } catch (e) { diff --git a/wrt_app/service/builtins/builtin_handler.ts b/wrt_app/service/builtins/builtin_handler.ts deleted file mode 100644 index de9c8a8..0000000 --- a/wrt_app/service/builtins/builtin_handler.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as vm from 'vm'; - -let sandbox: vm.Context = { - console: console, - require: require, - services: {} -}; - -export function handleService(service_name: string, service_id: string) { - if (!service_name) - return; - - let need_stop = (service_name.substr(0, 5) === 'stop_'); - if (need_stop) { - service_name = service_name.substr(5); - } - let builtin_service = `./${service_name}.js`; - console.log(`Builtin service is ${builtin_service}`); - let options = { - filename: service_id, - }; - if (need_stop) { - let code = `services['${service_id}'].stop('${service_id}')`; - vm.runInContext(code, sandbox); - } else { - let code = `services['${service_id}'] = require('${builtin_service}');`; - code += `services['${service_id}'].run('${service_id}')`; - vm.runInNewContext(code, sandbox, options); - } -} \ No newline at end of file diff --git a/wrt_app/service/builtins/wasm_builder.ts b/wrt_app/service/builtins/wasm_builder.ts index b61ed86..aa8a00f 100644 --- a/wrt_app/service/builtins/wasm_builder.ts +++ b/wrt_app/service/builtins/wasm_builder.ts @@ -1,5 +1,7 @@ -import * as fs from 'fs'; +import '../../common/init'; +import { isMainThread, 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})`); @@ -25,7 +27,6 @@ export function run(app_id: string) { }); } -export function stop(app_id: string) { - // TODO, stop caching will be implemented here - console.log(`wasm_builder.js suspended, app_id:(${app_id})`); -} \ No newline at end of file +if (!isMainThread) { + run(workerData.id); +} diff --git a/wrt_app/service/main.ts b/wrt_app/service/main.ts index 6fa2f41..b0c371a 100755 --- a/wrt_app/service/main.ts +++ b/wrt_app/service/main.ts @@ -19,7 +19,6 @@ import '../common/init'; import { wrt } from '../browser/wrt'; import * as ServiceManager from '../common/service_manager'; -import * as BuiltinService from './builtins/builtin_handler'; wrt.on('start-service', (event: any, internal_id: string) => { console.log('start service app : ' + internal_id); @@ -34,8 +33,8 @@ wrt.on('stop-service', (event: any, internal_id: string) => { }); wrt.on('builtin-service', (event: any, internal_id: string, service_name: string) => { - console.log(`service_name: ${service_name}`); - BuiltinService.handleService(service_name, internal_id); + console.log(`id: ${internal_id}, service_name: ${service_name}`); + ServiceManager.handleBuiltinService(internal_id, service_name); }); wrt.on('quit', (event: any) => { -- 2.7.4 From b6a74f93575992e34c406ae477fb00ba95f012f0 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 21 Sep 2020 17:13:22 +0900 Subject: [PATCH 12/16] [Service][TV] Refactor for wasm-caching shutdown 1) Calls delayShutdown() every wasm cache creation. - If built-in service is implemented with async functions, after run() is done and there is no running services, node main will be terminated by itself 1 minute later. delayShutdown() can reset the timeout to 1 min. 2) After finish wasm-caching, notify parent to terminate node worker - When wasm-caching is finished, node worker is able to terminate by stop messaging Change-Id: I23b3587d3f3746a451b517c7cd7a70c5f9593302 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 13 ++++++------- wrt_app/service/builtins/wasm_builder.ts | 7 +++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index b9daf4e..1ce2ea5 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -17,16 +17,12 @@ function isStandalone() { } function createWorker(id: string, startService: string, filename: string) { - if (workers[id]) { - console.log(`This worker is already running. ${id}`); - return; - } - workers[id] = new Worker(startService, { + return workers[id] ?? (workers[id] = new Worker(startService, { workerData: { id, filename } - }); + })); } function terminateWorker(id: string, delay: number) { @@ -85,7 +81,10 @@ export function handleBuiltinService(serviceId: string, serviceName: string) { if (isMainThread) { console.log(`Builtin service is ${serviceName}`); let startService = `${__dirname}/../service/builtins/${serviceName}.js`; - createWorker(serviceId, startService, ''); + let worker = createWorker(serviceId, startService, ''); + worker.on('stop', () => { + terminateWorker(serviceId, 0); + }); } } } \ No newline at end of file diff --git a/wrt_app/service/builtins/wasm_builder.ts b/wrt_app/service/builtins/wasm_builder.ts index aa8a00f..7ec30a3 100644 --- a/wrt_app/service/builtins/wasm_builder.ts +++ b/wrt_app/service/builtins/wasm_builder.ts @@ -1,5 +1,5 @@ import '../../common/init'; -import { isMainThread, workerData } from 'worker_threads'; +import { isMainThread, parentPort, workerData } from 'worker_threads'; import { wrt } from '../../browser/wrt'; import * as fs from 'fs'; @@ -19,12 +19,15 @@ export function run(app_id: string) { let tv = wrt.tv as NativeWRTjs.TVExtension; tv.setWasmFlags(); tv.setDiskCache(app_id); - tv.delayShutdown(); let files = tv.getWasmFiles(app_id); console.log(files); files.forEach((file_path: string) => { + tv.delayShutdown(); compileWasmForCaching(file_path); }); + if (parentPort) { + parentPort.postMessage('stop'); + } } if (!isMainThread) { -- 2.7.4 From 8b45240fb1eaea93bedf12079beff1a24eeaad59 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 9 Sep 2020 18:31:38 +0900 Subject: [PATCH 13/16] [Service] APIRouter - xwalk.util.checkPrivilegeAccess xwalk.util.checkPrivilegeAccess() is an internal API of webapis for checking the app has proper privilege. If the app hasn't required privilege, it will throw exception. For example, When 'tizen.filesystem.listStorages' is handled xwalk.utils.checkPrivilegeAccess( xwalk.utils.privilege.FILESYSTEM_READ); it checks if the app has 'filesystem.read' privilege, then, this overrided checkPrivilegeAccess() can inspect its privileges defined in config.xml. (not wrt-service's privileges) This is different from AccessControlManager's webapis drops. In webapis, there are two ways of privilege checking. 1) by xwalk.util.checkPrivilegeAccess() 2) by cynara inspection directly AccessControlManager purpose should be considered way #2. webapis's cynara DB checking, it always inspects on wrt-service's. Then, AccessControlManager should be able to disable webapis which the app doesn't have required privileges. Change-Id: I84ce85a580a483c209d354ca2f1b7c3d17c08fb3 Signed-off-by: DongHyun Song --- wrt_app/common/service_manager.ts | 11 ++++++----- wrt_app/common/service_runner.ts | 8 +++----- wrt_app/common/wrt_xwalk_extension.ts | 9 +++++++-- wrt_app/service/device_api_router.ts | 16 +++++++++++++--- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/wrt_app/common/service_manager.ts b/wrt_app/common/service_manager.ts index 1ce2ea5..3038364 100644 --- a/wrt_app/common/service_manager.ts +++ b/wrt_app/common/service_manager.ts @@ -5,15 +5,16 @@ interface WorkerMap { [id: string]: any; } let workers: WorkerMap = {}; -let serviceType: string = wrt.getServiceModel(); let runner: any; -function isGlobalService() { - return serviceType === 'DAEMON'; -} +global.serviceType = wrt.getServiceModel(); function isStandalone() { - return serviceType === 'STANDALONE'; + return global.serviceType === 'STANDALONE'; +} + +function isGlobalService() { + return global.serviceType === 'DAEMON'; } function createWorker(id: string, startService: string, filename: string) { diff --git a/wrt_app/common/service_runner.ts b/wrt_app/common/service_runner.ts index 7ea5bca..286297a 100644 --- a/wrt_app/common/service_runner.ts +++ b/wrt_app/common/service_runner.ts @@ -4,14 +4,12 @@ import { DeviceAPIRouter } from '../service/device_api_router'; import { isMainThread, parentPort, workerData } from 'worker_threads'; import { wrt } from '../browser/wrt'; -let serviceType: string = wrt.getServiceModel(); - function isServiceApplication() { - return serviceType !== 'UI'; + return global.serviceType !== 'UI'; } function isGlobalService() { - return serviceType === 'DAEMON'; + return global.serviceType === 'DAEMON'; } function registerExtensionResolver(id: string) { @@ -41,7 +39,7 @@ export function start(id: string, filename: string) { } }); - console.log('serviceType : '+serviceType) + console.log(`serviceType : ${global.serviceType}`) new DeviceAPIRouter(id, isGlobalService()); if (isServiceApplication()) { diff --git a/wrt_app/common/wrt_xwalk_extension.ts b/wrt_app/common/wrt_xwalk_extension.ts index 461e7dd..f7ba13d 100644 --- a/wrt_app/common/wrt_xwalk_extension.ts +++ b/wrt_app/common/wrt_xwalk_extension.ts @@ -117,14 +117,19 @@ class XWalkExtension { this.createNamespace(global, ext.name); var api = (ext.use_trampoline) ? api_ : global; - + var extension_api = ext.jsapi; + if (global.serviceType === 'DAEMON' && 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);', ''); + } const jscode = '(function(extension) {' + ' extension.internal = {};' + ' extension.internal.sendSyncMessage = extension.sendSyncMessage;' + ' delete extension.sendSyncMessage;' + ' var exports = {}; ' + - ' (function() {\'use strict\'; ' + ext.jsapi + '})();' + + ' (function() {\'use strict\'; ' + extension_api + '})();' + ' api.' + ext.name + ' = exports; ' + '});'; diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index 5d65aa3..b7a6e0f 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -14,6 +14,7 @@ export class DeviceAPIRouter { serviceId: string; packageId: string; callerAppId: string; + permissions: string[]; constructor(id: string, isGlobal: boolean) { this.id = id; @@ -21,6 +22,7 @@ export class DeviceAPIRouter { this.serviceId = ids[0]; this.callerAppId = ids[1] ?? ''; this.packageId = this.serviceId.split('.')[0]; + this.permissions = wrt.getPrivileges(this.id); this.initWebapis(); if (isGlobal) { @@ -28,6 +30,7 @@ export class DeviceAPIRouter { this.refinePackageApis(); this.refineFilesystemApis() this.initAccessControlManager(); + this.refineXwalkUtilApis(); } } @@ -50,10 +53,9 @@ export class DeviceAPIRouter { } initAccessControlManager() { - const permissions = wrt.getPrivileges(this.id); - console.log(`permissions : ${permissions}`); + console.log(`permissions : ${this.permissions}`); const AccessControlManager = require('./access_control_manager'); - AccessControlManager.initialize(permissions); + AccessControlManager.initialize(this.permissions); } getServiceId() { @@ -152,4 +154,12 @@ export class DeviceAPIRouter { global.tizen.filesystem.isDirectory = this.injectVirtualRootResolver(global.tizen.filesystem.isDirectory); global.tizen.filesystem.pathExists = this.injectVirtualRootResolver(global.tizen.filesystem.pathExists); } + + refineXwalkUtilApis() { + global.xwalk.utils.checkPrivilegeAccess = (privilege: string) => { + if (!this.permissions.includes(privilege)) { + throw 'Permission denied'; + } + } + } } -- 2.7.4 From ad5118f066c383a6bf22fc375a6e8b60ceeb3c03 Mon Sep 17 00:00:00 2001 From: Youngsoo Choi Date: Thu, 24 Sep 2020 04:48:29 -0700 Subject: [PATCH 14/16] [Service] Fix not returning handler id of systeminfo The systeminfo device API should return handler id to control listener later. Change-Id: Idc12f8164be0a500a29b1a272899148e3c17aff7 Signed-off-by: Youngsoo Choi --- wrt_app/service/access_control_manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrt_app/service/access_control_manager.ts b/wrt_app/service/access_control_manager.ts index 120fe1c..87afb7a 100644 --- a/wrt_app/service/access_control_manager.ts +++ b/wrt_app/service/access_control_manager.ts @@ -6,7 +6,7 @@ function checkSystemInfoApiPrivilege(func: any, permissions: string[]) { console.log('The telephony permission is missing.'); return ; } - override_func.call(global.tizen.systeminfo, ...args); + return override_func.call(global.tizen.systeminfo, ...args); } } -- 2.7.4 From b778ba1661387e54d89fe9007fa0831db1def900 Mon Sep 17 00:00:00 2001 From: Aron kim Date: Thu, 24 Sep 2020 19:19:38 -0700 Subject: [PATCH 15/16] [D2D] Change path for app routing. The installation path of the built-in deviceWebServer is changed. Reroute according to the changed path. Change-Id: I54b9004811a14e22aba5263921510b1798e43412 Signed-off-by: Aron kim --- d2d_app/service/app_router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d2d_app/service/app_router.js b/d2d_app/service/app_router.js index f9dd99d..56a5c51 100644 --- a/d2d_app/service/app_router.js +++ b/d2d_app/service/app_router.js @@ -3,7 +3,7 @@ var express = require('express'); class AppRouter { constructor(app, path) { var appRouter = express.Router(); - appRouter.use(express.static(__dirname + '/../../../../' + path + '/res/wgt/client')); + appRouter.use(express.static('/opt/usr/globalapps/' + path + '/res/wgt/client')); appRouter.get('/', (req, res) => { res.redirect('client.html'); -- 2.7.4 From 05a663a54e531739ca85dd55ad8cf44811e77d7b Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 10 Sep 2020 09:36:51 +0900 Subject: [PATCH 16/16] [Service][TV] Add TV productinfo webapis Add webapis.productinfo of TV profile. Related chromium-efl patch: https://review.tizen.org/gerrit/238981/ Change-Id: I1c865e7d0b2f2708f09e4de504a52836585c7090 Signed-off-by: DongHyun Song --- wrt_app/service/device_api_router.ts | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index b7a6e0f..42a57f3 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -50,6 +50,44 @@ export class DeviceAPIRouter { global.webapis.getPackageId = () => { return this.packageId; } + this.initProductWebapis(); + } + + initProductWebapis() { + // for TV profile + if (wrt.tv && !global.webapis.productinfo) { + global.webapis.cachedProperty = global.webapis.cachedProperty ?? {}; + let getCachedValue = (name: string) => { + if (global.webapis.cachedProperty[name]) { + return global.webapis.cachedProperty[name]; + } + let tv = wrt.tv as NativeWRTjs.TVExtension; + return (global.webapis.cachedProperty[name] = tv.queryProductValue(name)); + } + global.webapis.productinfo = { + getDuid: () => { + return getCachedValue('getDuid'); + }, + getFirmware: () => { + return getCachedValue('getFirmware'); + }, + getLocalSet: () => { + return getCachedValue('getLocalSet'); + }, + getModel: () => { + return getCachedValue('getModel'); + }, + getModelCode: () => { + return getCachedValue('getModelCode'); + }, + getRealModel: () => { + return getCachedValue('getRealModel'); + }, + getSmartTVServerVersion: () => { + return getCachedValue('getSmartTVServerVersion'); + } + }; + } } initAccessControlManager() { -- 2.7.4