[Tizen 7.0] Sync up branches from tizen_6.5 to tizen
[platform/framework/web/wrtjs.git] / wrt_app / service / service_manager.ts
1 import { Worker, isMainThread } from 'worker_threads';
2 import { wrt } from '../browser/wrt';
3 import * as XWalkExtension from '../common/wrt_xwalk_extension';
4
5 interface WorkerMap {
6   [id: string]: any;
7 }
8 let workers: WorkerMap = {};
9 let dyingWorkerQueue: WorkerMap = {};
10
11 Object.defineProperty(global, 'serviceType', {
12   value: wrt.getServiceModel(),
13   writable: false
14 });
15
16 function checkDyingWorker() {
17   let dyingWorkers = Object.keys(dyingWorkerQueue);
18   if (dyingWorkers.length) {
19     let workerId = dyingWorkers[0];
20     if (dyingWorkerQueue[workerId] === 'will-terminate') {
21       dyingWorkerQueue[workerId] = 'terminated';
22       workers[workerId].terminate();
23     }
24   }
25 }
26
27 function createWorker(id: string, startService: string, filename: string) {
28   if (workers[id]) {
29     workers[id].postMessage({ type: 'wake' });
30     return;
31   }
32
33   wrt.tv?.serviceMount(id);
34   workers[id] = new Worker(startService, {
35     workerData: {
36       id,
37       filename
38     }
39   });
40   workers[id].on('message', (message: string) => {
41     if (message === 'will-terminate') {
42       dyingWorkerQueue[id] = message;
43       checkDyingWorker();
44     }
45   });
46   workers[id].on('exit', (code: number) => {
47     wrt.tv?.serviceUmount(id);
48     delete dyingWorkerQueue[id];
49     delete workers[id];
50     let runningServices = Object.keys(workers);
51     console.debug(`${id} terminated, remain services(${runningServices})`);
52     checkDyingWorker();
53   });
54 }
55
56 function terminateWorker(id: string, delay: number) {
57   if (!workers[id]) {
58     console.debug(`This worker is already terminated. ${id}`);
59     return;
60   }
61   console.debug(`${id} will shutdown after ${delay}ms`);
62   workers[id].postMessage({ type: 'stop', delay });
63 }
64
65 let initializeExtensionOnMain = () => {
66   initializeExtensionOnMain = () => {};
67   XWalkExtension.initialize();
68   // This is workaround solution to make webapis's singleton worker, which has
69   // same smack label with pid's.
70   // It must be handled ahead of dropThreadPrivilege()
71   // Otherwise, smack violation might hanppen from 'libdbuspolicy'.
72   global.tizen.systeminfo.getPropertyValue("CPU", () => { }, () => { });
73 }
74
75 export function startService(id: string, filename: string) {
76   console.debug(`startService - ${id}`);
77   initializeExtensionOnMain();
78   if (global['serviceType'] === 'STANDALONE') {
79     let ids = id.split(':');
80     let serviceId = ids[0];
81     let packageId = serviceId.split('.')[0];
82     wrt.security?.dropThreadPrivilege(packageId, serviceId);
83   }
84   let startService = `${__dirname}/service_runner.js`;
85   createWorker(id, startService, filename);
86 }
87
88 export function stopService(id: string) {
89   console.debug(`stopService - ${id}`);
90   terminateWorker(id, 500);
91 }
92
93 export function handleBuiltinService(serviceId: string, serviceName: string) {
94   if (!serviceName) {
95     return;
96   }
97   let need_stop = (serviceName.substr(0, 5) === 'stop_');
98   if (need_stop) {
99     console.debug(`${serviceName} will be terminated.`);
100     workers[serviceId].terminate();
101   } else {
102     console.debug(`Builtin service is ${serviceName}`);
103     let startService = `${__dirname}/../service/builtins/${serviceName}.js`;
104     createWorker(serviceId, startService, '');
105   }
106 }