UNPKG

@webos-tools/cli

Version:

Command Line Interface for development webOS application and service

1,007 lines (935 loc) 69.8 kB
/* * Copyright (c) 2020-2024 LG Electronics Inc. * * SPDX-License-Identifier: Apache-2.0 */ const async = require('async'), chalk = require('chalk'), createCsvWriter = require('csv-writer').createObjectCsvWriter, fs = require('fs'), npmlog = require('npmlog'), path = require('path'), streamBuffers = require('stream-buffers'), Table = require('easy-table'), util = require('util'), pullLib = require('./pull'), errHndl = require('./base/error-handler'), luna = require('./base/luna'), novacom = require('./base/novacom'), createDateFileName = require('./util/createFileName').createDateFileName, convertJsonToList = require('./util/json').convertJsonToList; (function() { const log = npmlog; log.heading = 'device'; log.level = 'warn'; const device = { /** * @property {Object} log an npm log instance */ log: log, /** * Print system information of the given device * @property options {String} device the device to connect to */ systemInfo: function(options, next) { if (typeof next !== 'function') { throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next)); } options = options || {}; async.series([ _makeSession, _getOsInfo, _getDeviceInfo, _getChromiumVersion, _getQtbaseVersion, _getSoftwareInfo ], function(err, results) { log.silly("device#systemInfo()", "err:", err, ", results:", results); let resultTxt = ""; for (let i = 1; i < results.length; i++) { resultTxt += results[i] + "\n"; } next(err, {msg: resultTxt.trim()}); }); function _makeSession(next) { makeSession(options, next); } function _getOsInfo(next) { log.info("device#systemInfo()#_getOsInfo()"); const target = options.session.getDevice(), addr = target.lunaAddr.osInfo, param = { // luna param parameters:["webos_build_id","webos_imagename","webos_name","webos_release", "webos_manufacturing_version", "core_os_kernel_version"], subscribe: false }; luna.send(options, addr, param, function(lineObj, next) { const resultValue = lineObj; if (resultValue.returnValue) { log.verbose("device#systemInfo()#_getOsInfo()", "success"); delete resultValue.returnValue; // remove unnecessary data next(null, _makeReturnTxt(resultValue)); } else { log.verbose("device#systemInfo()#_getOsInfo()", "failure"); next(errHndl.getErrMsg("INVALID_OBJECT")); } }, next); } function _getDeviceInfo(next) { log.info("device#systemInfo()#_getDeviceInfo()"); const target = options.session.getDevice(), addr = target.lunaAddr.deviceInfo, param = { // luna param subscribe: false }; luna.send(options, addr, param, function(lineObj, next) { const resultValue = lineObj, returnObj ={}; if (resultValue.returnValue) { log.verbose("device#systemInfo()#_getDeviceInfo()", "success"); returnObj.device_name = resultValue.device_name; returnObj.device_id = resultValue.device_id; next(null, _makeReturnTxt(returnObj)); } else { log.verbose("device#systemInfo()#_getDeviceInfo()", "failure"); next(errHndl.getErrMsg("INVALID_OBJECT")); } }, next); } function _getChromiumVersion(next) { log.info("device#systemInfo()#_getChromiumInfo()"); // opkg is required permission as root. if (options.session.getDevice().username !== 'root') { return next(null, "chromium_version : " + "not supported"); } else { const cmd = '/usr/bin/opkg list-installed webruntime*'; options.session.run(cmd, null, __data, null, function(err) { if (err) { return next(err); } }); } function __data(data) { const str = (Buffer.isBuffer(data)) ? data.toString() : data, exp = /\d*\.\d*\.\d*\.\d*/, version = str.match(exp); next(null, "chromium_version : " + version); } } function _getQtbaseVersion(next) { log.info("device#systemInfo()#_getQtbaseInfo()"); // opkg is required permission as root. if (options.session.getDevice().username !== 'root') { return next(null, "qt_version : " + "not supported"); } else { const cmd = '/usr/bin/opkg list-installed qtbase'; options.session.run(cmd, null, __data, null, function(err) { if (err) { return next(err); } }); } function __data(data) { const str = (Buffer.isBuffer(data)) ? data.toString() : data, exp = /\d*\.\d*\.\d*/, version = str.match(exp); next(null, "qt_version : " + version); } } function _getSoftwareInfo(next) { log.info("device#systemInfo#_getSoftwareInfo()"); const target = options.session.getDevice(), addr = target.lunaAddr.softwareInfo, param = { parameters: ["nodejs_versions"] }; luna.sendWithoutErrorHandle(options, addr, param, function(lineObj, next) { log.silly("device#systemInfo#_getSoftwareInfo():", "lineObj:", lineObj); const resultValue = lineObj, returnObj ={}; if (resultValue.returnValue) { log.verbose("device#systemInfo#_getSoftwareInfo():", "success"); returnObj.nodejs_versions = resultValue.nodejs_versions; next(null, _makeReturnTxt(returnObj)); } else { // handle if the target device does not support softwareInfo/query return next(null, "nodejs_versions : " + "not supported"); } }, next); } function _makeReturnTxt(resultValue) { let returnTxt = ""; for (const key in resultValue) { if (resultValue[key] === undefined) { resultValue[key] = "(unknown)"; } returnTxt += key + " : " + resultValue[key] + "\n"; } return returnTxt.trim(); } }, /** * Print session information of the given device * @property options {String} device the device to connect to */ sessionInfo: function(options, next) { if (typeof next !== 'function') { throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next)); } options = options || {}; async.series([ _makeSession, _getSessionList ], function(err, results) { log.silly("device#sessionInfo()", "err:", err, ", results:", results); let resultTxt = ""; if (results[1] !== undefined) { if (typeof results[1] === "object") { if (results[1].length === 0) { return next(errHndl.getErrMsg("SELECT_PROFILE")); } for (let i = 0; i < results[1].length; i++) { resultTxt += convertJsonToList(results[1][i], 0) + '\n'; } } else { resultTxt = results[1]; } } next(err, {msg: resultTxt.trim()}); }); function _makeSession(next) { makeSession(options, next); } function _getSessionList(next) { log.info("device#sessionInfo#_getSessionList()"); const target = options.session.getDevice(), addr = target.lunaAddr.getSessionList, param = { // luna param subscribe: false }; luna.send(options, addr, param, function(lineObj, next) { if (lineObj.returnValue) { log.verbose("device#sessionInfo()#_getSessionList()", "success"); next(null, lineObj.sessionList); } else { log.verbose("device#sessionInfo()#_getSessionList()", "failure"); next(errHndl.getErrMsg("INVALID_OBJECT")); } }, next); } }, /** * Print system information of the given device * @property options {String} device the device to connect to */ tvSystemInfo: function(options, next) { if (typeof next !== 'function') { throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next)); } options = options || {}; async.series([ _makeSession, _getSystemInfo, ], function(err, results) { log.silly("device#tvSystemInfo()", "err:", err, ", results:", results); next(err, {msg: results[1]}); }); function _makeSession(next) { makeSession(options, next); } function _getSystemInfo(next) { log.info("device#tvSystemInfo#_getSystemInfo()"); const target = options.session.getDevice(), addr = target.lunaAddr.deviceInfoSystem, param = { // luna param keys: ["modelName", "sdkVersion", "firmwareVersion", "boardType", "otaId"], subscribe: false }; luna.sendWithoutErrorHandle(options, addr, param, function (lineObj, next) { if (lineObj) { log.verbose("deviceInfo#systemInfo#_getSystemInfo():", "success"); next(null, __makeReturnObj(lineObj, param.keys)); } else { next(errHndl.getErrMsg("INVALID_OBJECT")); } }, next); } function __makeReturnObj(resultValue, paramkey) { let returnTxt = ""; for (const key in paramkey) { if (Object.hasOwnProperty.call(resultValue, paramkey[key])) returnTxt += paramkey[key] + " : " + resultValue[paramkey[key]] + "\n"; } log.verbose("deviceInfo#systemInfo#__makeReturnObj():", returnTxt); return returnTxt.trim(); } }, /** * Get all CPUs and memories usage of target device * @property options {String} device, interval */ systemResource: function(options, next) { if (typeof next !== 'function') { throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next)); } const systemGroup = {}; systemGroup.initialExecution = true; options = options || {}; options.destinationPath = ""; options.fileName = ""; options.csvPath = ""; async.series([ _createOutputPath, _makeSession, _getSystemResouceInfo ], function(err, results) { log.silly("device#systemResource()", "err:", err, ", results:", results); next(err); }); function _createOutputPath(next) { if (options.save && options.csvPath === "") { makeCSVOutputPath(options, next); } else { next(); } } function _makeSession(next) { makeSession(options, next); } function _getSystemResouceInfo(next) { log.info("device#systemResource()#_getSystemResouceInfo()"); let timerId; if (!options.interval) { // If interval option is not given, call timer logic 2 times const defaultRepeat = 2; let repeatCount = 0; try { timerId = setTimeout(function repeat() { if (repeatCount < defaultRepeat) { _callSystemResourceInfoCmd(); repeatCount++; timerId = setTimeout(repeat, 1000); } else { clearTimeout(timerId); return next(); } }, 100); } catch (err) { log.silly("device#systemResource()#_getSystemResouceInfo()", "one timer. err:", err.toString()); clearTimeout(timerId); // ignore timer logic error return next(); } } else { try { // when interval option is given, print initial data at first const defaultRepeat = 1; let repeatCount = 0; timerId = setTimeout(function repeat() { if (repeatCount < defaultRepeat) { _callSystemResourceInfoCmd(); repeatCount++; timerId = setTimeout(repeat, 1000); } else { _callSystemResourceInfoCmd(); timerId = setTimeout(repeat, options.interval * 1000); } }, 100); } catch (err) { log.silly("device#systemResource()#_getSystemResouceInfo()", "repeat timer. err:", err.toString()); clearTimeout(timerId); // ignore timer logic error return next(); } } } function _callSystemResourceInfoCmd() { log.info("device#systemResource()#_callSystemResourceInfoCmd()"); const wStream = new streamBuffers.WritableStreamBuffer(); const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep -c ^processor /proc/cpuinfo; grep "cpu *" /proc/stat; free -k'; try { options.session.run(cmd, null, wStream, null, function(err) { if (err) { // do not print error message to user // when user press Ctrl + C , the ssh connection is not completed, it makes error log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "ssh call. err:"+ err.toString()); return next(); } else { const result = wStream.getContentsAsString(); _setSystemResouceInfo(result); systemGroup.initialExecution = false; } }); } catch (err) { // do not print error message to user // when user press Ctrl + C , the ssh connection is not completed, it makes error log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "in try-catch. err:", err.toString()); return next(); } } function _setSystemResouceInfo(systemData) { log.info("device#systemResource()#_callSystemResourceInfoCmd()"); const CPU_PATTERN = /\s+/, cpuinfo = {}, meminfo = {}; let sysinfo = {}; try { const allvalues = systemData.split("\n"), date = allvalues[0], // Setup date pcore = +allvalues[1] * 100; let index, columns, isBuff_Cached = false; // This is to check the format version of kernel to find system memory parameter for (index = 2; index < (allvalues.length - 1); index++) { columns = allvalues[index].split(CPU_PATTERN); // setup CPU information if (columns[0].indexOf("cpu") === 0) { const prevTotal = "prev" + columns[0] + "Total", prevIdle = "prev" + columns[0] + "Idle", prevUser = "prev" + columns[0] + "User", prevkernel = "prev" + columns[0] + "Kernel", prevOther = "prev" + columns[0] + "Other"; if (!systemGroup[prevTotal]) { systemGroup[prevTotal] = 0; systemGroup[prevIdle] = 0; systemGroup[prevUser] = 0; systemGroup[prevkernel] = 0; systemGroup[prevOther] = 0; } const user = parseInt(columns[1]), nice = parseInt(columns[2]), kernel = parseInt(columns[3]), idle = parseInt(columns[4]), other = nice + parseInt(columns[5]) + parseInt(columns[6]) + parseInt(columns[7]) + parseInt(columns[8]) + parseInt(columns[9]) + parseInt(columns[10]), subTotal = user + nice + kernel + idle + other; if (!systemGroup.initialExecution) { const diffIdle = idle - systemGroup[prevIdle], diffUser = user - systemGroup[prevUser], diffKernel = kernel - systemGroup[prevkernel], diffOther = other - systemGroup[prevOther], diffTotal = subTotal - systemGroup[prevTotal]; let userModeCpuOccupation = (diffUser/diffTotal) * 100, kernelModeCpuOccupation = (diffKernel/diffTotal) * 100, otherModeCpuOccupation = (diffOther/diffTotal) * 100, overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100; userModeCpuOccupation < 0 ? (userModeCpuOccupation = 0) : userModeCpuOccupation; userModeCpuOccupation > pcore ? (userModeCpuOccupation = pcore) : userModeCpuOccupation; kernelModeCpuOccupation < 0 ? (kernelModeCpuOccupation = 0) : kernelModeCpuOccupation; kernelModeCpuOccupation > pcore ? (kernelModeCpuOccupation = pcore) : kernelModeCpuOccupation; otherModeCpuOccupation < 0 ? (otherModeCpuOccupation = 0) : otherModeCpuOccupation; otherModeCpuOccupation > pcore ? (otherModeCpuOccupation = pcore) : otherModeCpuOccupation; overallCpuOccupation < 0 ? (overallCpuOccupation = 0) : overallCpuOccupation; overallCpuOccupation > pcore ? (overallCpuOccupation = pcore) : overallCpuOccupation; cpuinfo[columns[0]] = { "overall": +overallCpuOccupation.toFixed(2), "usermode": +userModeCpuOccupation.toFixed(2), "kernelmode": +kernelModeCpuOccupation.toFixed(2), "others": +otherModeCpuOccupation.toFixed(2) }; } systemGroup[prevIdle] = idle; systemGroup[prevUser] = user; systemGroup[prevkernel] = kernel; systemGroup[prevOther] = other; systemGroup[prevTotal] = subTotal; } if (!systemGroup.initialExecution) { // setup memory infomation if (columns[5] && columns[5].indexOf('buff/cache') !== -1) { isBuff_Cached = true; } if (columns[0].indexOf('Mem:') === 0) { meminfo['memory'] = !isBuff_Cached ? { "total": +columns[1], "used": +columns[2], "free": +columns[3], "shared": +columns[4], "buffers": +columns[5], "cached": +columns[6] } : { "total": +columns[1], "used": +columns[2], "free": +columns[3], "shared": +columns[4], "buff_cache": +columns[5], "available": +columns[6] }; } if (columns[0].indexOf('-/+') === 0) { meminfo['buffers'] = { "used": +columns[2], "free": +columns[3] }; } if (columns[0].indexOf('Swap:') === 0) { meminfo['swap'] = { "total": +columns[1], "used": +columns[2], "free": +columns[3] }; } } } if (!systemGroup.initialExecution) { sysinfo = { "date": date, "cpuinfo": cpuinfo, "meminfo": meminfo }; _printSystemInfo(sysinfo); } } catch (err) { // do not print error message to user // when user press Ctrl + C , the ssh cmd data is not completed, it makes error log.silly("device#systemResource()#_setSystemResouceInfo()", "in try-catch. err:", err.toString()); return; } } function _printSystemInfo(sysinfo) { const cpuinfo = sysinfo.cpuinfo, meminfo = sysinfo.meminfo, cpuinfoTable = new Table(), meminfoTable = new Table(), dataForCSV = []; // add CPU info to the table for (const key in cpuinfo) { cpuinfoTable.cell('(%)', key); cpuinfoTable.cell('overall', cpuinfo[key].overall); cpuinfoTable.cell('usermode', cpuinfo[key].usermode); cpuinfoTable.cell('kernelmode', cpuinfo[key].kernelmode); cpuinfoTable.cell('others', cpuinfo[key].others); cpuinfoTable.newRow(); // Add csv array const obj = { time: sysinfo.date, cpu: key, overall: cpuinfo[key].overall, usermode: cpuinfo[key].usermode, kernelmode: cpuinfo[key].kernelmode, others: cpuinfo[key].others }; dataForCSV.push(obj); } // add memoryInfo to the table for (const key in meminfo) { meminfoTable.cell('(KB)', key); meminfoTable.cell('total', meminfo[key].total); meminfoTable.cell('used', meminfo[key].used); meminfoTable.cell('free', meminfo[key].free); meminfoTable.cell('shared', meminfo[key].shared); meminfoTable.cell('buff/cache', meminfo[key].buff_cache); meminfoTable.cell('available', meminfo[key].available); meminfoTable.newRow(); const obj = { time: sysinfo.date, memory: key, total: meminfo[key].total, used: meminfo[key].used, free: meminfo[key].free, shared: meminfo[key].shared, "buff/cache": meminfo[key].buff_cache, available: meminfo[key].available }; dataForCSV.push(obj); } // write CSV file if user gives --save option if (options.save && options.csvPath) { // write csv file // when openMode is false, the new csv file will be created and "Header" add to the file let openMode = false; if (fs.existsSync(options.csvPath)) { openMode = true; } const csvWriter = createCsvWriter({ path: options.csvPath, header: [ {id: 'time', title: 'time'}, {id: 'cpu', title: '(%)'}, {id: 'overall', title: 'overall'}, {id: 'usermode', title: 'usermode'}, {id: 'kernelmode', title: 'kernelmode'}, {id: 'others', title: 'others'}, {id: 'memory', title: '(KB)'}, {id: 'total', title: 'total'}, {id: 'used', title: 'used'}, {id: 'free', title: 'free'}, {id: 'shared', title: 'shared'}, {id: 'buff/cache', title: 'buff/cache'}, {id: 'available', title: 'available'} ], append: openMode }); csvWriter .writeRecords(dataForCSV) .then(function() { log.silly("device#systemResource()#_printSystemInfo()", "CSV file updated"); // csv file has been created at first if (openMode === false) { const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath; console.log(resultTxt); } __printTable(); }).catch(function(err) { return setImmediate(next, errHndl.getErrMsg(err)); }); } else { __printTable(); } function __printTable() { console.log(sysinfo.date + "\n"); console.log(cpuinfoTable.toString()); console.log(meminfoTable.toString()); console.log("================================================================="); } } }, /** * Get running apps and services CPUs and memories usage * @property options {String} device, interval */ processResource: function(options, next) { if (typeof next !== 'function') { throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next)); } const processGroup = {}; processGroup.initialExecution = true; options = options || {}; options.destinationPath = ""; options.fileName = ""; options.csvPath = ""; async.series([ _createOutputPath, _makeSession, _getProcessResouceInfo ], function(err, results) { log.silly("device#processResource()", "err:", err, ", results:", results); next(err); }); function _createOutputPath(next) { if (options.save && options.csvPath === "") { makeCSVOutputPath(options, next); } else { next(); } } function _makeSession(next) { makeSession(options, next); } function _getProcessResouceInfo(next) { log.info("device#processResource()#_getProcessResouceInfo()"); let timerId; if (!options.interval) { // If interval option is not given, call timer logic 2 times const defaultRepeat = 2; let repeatCount = 0; try { timerId = setTimeout(function repeat() { if (repeatCount < defaultRepeat) { _callProcessInfoCmd(); repeatCount++; timerId = setTimeout(repeat, 1000); } else { clearTimeout(timerId); return next(); } }, 100); } catch (err) { log.silly("device#systemResource()#_getProcessResouceInfo()", "one timer. err:", err.toString()); clearTimeout(timerId); // ignore timer logic error return next(); } } else { try { // when interval option is given, print initial data at first const defaultRepeat = 1; let repeatCount = 0; timerId = setTimeout(function repeat() { if (repeatCount < defaultRepeat) { _callProcessInfoCmd(); repeatCount++; timerId = setTimeout(repeat, 1000); } else { _callProcessInfoCmd(); timerId = setTimeout(repeat, options.interval * 1000); } }, 100); } catch (err) { log.silly("device#systemResource()#_getProcessResouceInfo()", "repeat timer. err:", err.toString()); clearTimeout(timerId); // ignore timer logic error return next(); } } } function _callProcessInfoCmd() { log.info("device#processResource()#_callProcessInfoCmd()"); const wStream = new streamBuffers.WritableStreamBuffer(); const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep "cpu *" /proc/stat | sed "1d" | awk \'{for (i=0;i<NR;i++){if (i==NR-1){totalSum+=$2+$3+$4+$5+$6+$7+$8+$9+$10+$11;idleSum+=$5}}} END { for (i=0;i<NR;i++){if (i==NR-1){print idleSum;print totalSum}}}\'; cat /proc/[0-9]*/stat; echo \'psList\' ; ps -ax | sed "1d" | awk \'/ /{print $1 "\t"$5}\'; echo \'serviceStringStart\'; ls /media/developer/apps/usr/palm/services ; echo \'serviceStringEnd\'; luna-send-pub -n 1 -f luna://com.webos.applicationManager/dev/running \'{}\'; grep -c ^processor /proc/cpuinfo'; try { options.session.run(cmd, null, wStream, null, function(err) { if (err) { // do not print error message to user // when user press Ctrl + C , the ssh connection is not completed, it makes error log.silly("device#processResource()#_callProcessInfoCmd()", "ssh call. err:", err.toString()); return next(null); } else { const result = wStream.getContentsAsString(); _setProcessInfo(result); processGroup.initialExecution = false; } }); } catch (err) { // do not print error message to user // when user press Ctrl + C , the ssh connection is not completed, it makes error log.silly("device#processResource()#_callProcessInfoCmd()", "in try-catch. err:", err.toString()); return next(null); } } function _setProcessInfo(processData) { log.info("device#processResource()#_setProcessInfo()"); const PROC_GROUP_INFO_PATTERN = /\s+/; try { // Intialize temporary groups with values const processList = ["Service", "System"], groupProcessList = [], tempProcGrps = {}, arrActiveServices = []; // loop through all the categories and create groups for (let i = 0; i < processList.length; i++) { tempProcGrps[processList[i]] = {}; tempProcGrps[processList[i]]["pid"] = 0; tempProcGrps[processList[i]]["cputime"] = 0; tempProcGrps[processList[i]]["RSS"] = 0; tempProcGrps[processList[i]]["pmem"] = 0; } const processinfo = [], groupProcessinfo = [], // only for dev app & service info allvalues = processData.split("\n"), otherList = [], date = allvalues[0], lastIndex = allvalues.length; allvalues.splice(lastIndex - 1, 1); const pcore = +allvalues[allvalues.length-1] * 100; /* memCol[1] from 'grep "MemTotal *" /proc/meminfo' is not used */ let totalRAM = 0; const idleCPUtime = +allvalues[1], totalCPUtime = +allvalues[2], psListStartIndex = allvalues.indexOf("psList", 2), serviceStartIndex = allvalues.indexOf("serviceStringStart", 2), // from where to start (2) serviceEndIndex = allvalues.indexOf("serviceStringEnd", 2); // from where to start (2) const arryInstalledServices = []; for (let i = serviceStartIndex + 1; i < serviceEndIndex; i++) { arryInstalledServices[i-serviceStartIndex-1] = allvalues[i]; } // get processid of external service on ps list let arrayCount = 0; for (let k = psListStartIndex+1 ; k < serviceStartIndex ;k++) { const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN), pid = parseInt(columns[0]), procname = columns[1].trim(); if (arryInstalledServices.indexOf(procname) !== -1) { const ObjService = { "processid": pid, "id": procname }; arrActiveServices[arrayCount++] = ObjService; } } const appStartIndex = allvalues.indexOf("{", 2); // From where to start (2) // some times specific platform does not gives list of running info itself then appStartIndex becomes -1 if (appStartIndex < 0) { // do not print error message to user // when user press Ctrl + C , the ssh cmd data is not completed, it makes error log.silly("device#processResource()#_setProcessInfo()", "running app list is invalid"); return; } const appEndIndex = allvalues.length-1; let strActiveApps = "", objActiveApps; for (let i = appStartIndex; i < appEndIndex; i++) { strActiveApps += allvalues[i]; } try { objActiveApps = JSON.parse(strActiveApps); } catch (err) { // do not print error message to user // when user press Ctrl + C , the ssh cmd data is not completed, it makes error log.silly("device#processResource()#_setProcessInfo()", "active app parsing. err:", err.toString()); return; } if (objActiveApps.returnValue === false) { const errValue = objActiveApps["errorText"] || "running app list is invalid"; return next(errHndl.getErrMsg("FAILED_CALL_LUNA", errValue, null, "com.webos.applicationManager")); } const arrActiveApps = objActiveApps["running"], groupObjList = {}; // 1st row is date, 2nd row is total CPU time and last row is total RAM(Meminfo) hence ignore it // check process group info until "psList" string for (let k = 3; k < psListStartIndex; k++) { const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN), procname = columns[1].trim().split(/.*\(|\)/gi)[1], grpname = _getProcessGrp(procname), pid = parseInt(columns[0]), pname = procname, ppid = parseInt(columns[3]), cputime = parseInt(columns[13]) + parseInt(columns[14]), rss = parseInt(columns[23]) * 4, pmem = (rss * 100); // sum total used RSS totalRAM += rss; if (grpname === "Other") { const objOther = {}; objOther["pid"] = pid; objOther["pname"] = pname; objOther["ppid"] = ppid; objOther["cputime"] = cputime; objOther["RSS"] = rss; objOther["pmem"] = pmem; otherList.push(objOther); } else { tempProcGrps[grpname]["pid"] = pid; tempProcGrps[grpname]["cputime"] += cputime; tempProcGrps[grpname]["RSS"] += rss; tempProcGrps[grpname]["pmem"] += pmem; } } // get the Children of Service for (const k in tempProcGrps) { const attrName = k; if (attrName === "System") { continue; } const objOther = tempProcGrps[k]; for (let i = 0; i < otherList.length; i++) { if (objOther["pid"] !== otherList[i]["ppid"]) { continue; } } } // this variable will mantain the aggregate pcpuVal of Service + dynamic apps let aggcpuVal = 0; // get the Web App processes data if (arrActiveApps.length === 0) { // get only the existing categories(3) if no running apps. // dispose all the existing process variables for (const name in processGroup) { // if propertyName starts with "prev_" then dispose it if (!Object.prototype.hasOwnProperty.call(processGroup, name)) { continue; } if (name.indexOf("prev_app_") >= 0) { processGroup[name] = undefined; } } } else { // loop through each of the running apps // in loop - Check if app is newly running app (or) already existing running app for (let j = 0; j < arrActiveApps.length; j++) { const objActApp = arrActiveApps[j], webprocId = objActApp["webprocessid"], procId = objActApp["processid"], displayId = objActApp["displayId"] || 0; let processId; if (webprocId !== "" && webprocId !== undefined && webprocId !== "undefined") { processId = webprocId; } else if (procId !== "" && procId !== undefined && procId !== "undefined") { processId = procId; } else { break; } const prevcpuTime = "prev_app_" + processId + "cputime", appid = parseInt(processId); let pcputime = 0; // get the cputime from otherList for (let l = 0; l < otherList.length; l++) { if (otherList[l]["pid"] !== appid) { continue; } pcputime = otherList[l]["cputime"]; if (!processGroup[prevcpuTime]) { processGroup[prevcpuTime] = pcputime; break; } let webpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime)); // restrict showing the negative % values by making lowest to be zero. if (webpcpuval < 0 || webpcpuval === undefined || isNaN(webpcpuval)) webpcpuval = 0; aggcpuVal += webpcpuval; const groupListAppKey = objActApp["id"]+ "-" + appid; groupObjList[groupListAppKey] = { "id": objActApp["id"], "pid": appid, "cpu": webpcpuval, "memory": { "size": otherList[l]["RSS"], "percent": otherList[l]["pmem"].toFixed(2) }, "displayId": displayId }; processGroup[prevcpuTime] = pcputime; otherList.splice(l, 1); break; } } } // get the service processes data if (arrActiveServices.length === 0) { // get only the existing categories(3) if no running apps. // dispose all the existing process variables for (const name in processGroup) { // if propertyName starts with "prev_" then dispose it if (!Object.prototype.hasOwnProperty.call(processGroup, name)) { continue; } if (name.indexOf("prev_svc_") >= 0) { processGroup[name] = undefined; } } } else { // loop through each of the running apps // in loop - Check if app is newly running app (or) already existing running app for (let j = 0; j < arrActiveServices.length; j++) { const objActService = arrActiveServices[j], processId = objActService["processid"], prevcpuTime = "prev_svc_" + processId + "cputime", appid = parseInt(processId); let pcputime = 0; // get the cputime from otherList for (let l = 0; l < otherList.length; l++) { if (otherList[l]["pid"] !== appid) { continue; } pcputime = otherList[l]["cputime"]; if (!processGroup[prevcpuTime]) { processGroup[prevcpuTime] = pcputime; break; } let svcpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime)); // restrict showing the negative % values by making lowest to be zero. if (svcpcpuval < 0 || svcpcpuval === undefined || isNaN(svcpcpuval)) svcpcpuval = 0; aggcpuVal+= svcpcpuval; groupObjList[objActService["id"]] = { "pid": appid, "cpu": svcpcpuval, "memory": { "size": otherList[l]["RSS"], "percent": otherList[l]["pmem"].toFixed(2) } }; processGroup[prevcpuTime] = pcputime; otherList.splice(l, 1); break; } } } // get the remaining System Category processes for (let i = 0; i < otherList.length; i++) { tempProcGrps["System"]["pid"] = otherList[i]["pid"]; tempProcGrps["System"]["cputime"]+= otherList[i]["cputime"]; tempProcGrps["System"]["RSS"]+= otherList[i]["RSS"]; tempProcGrps["System"]["pm