RDK Documentation (Open Sourced RDK Components)
dcaproc.c
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 
21 
22 /**
23  * @defgroup dca
24  * @{
25  **/
26 
27 
28 
29 
30 /**
31  * @defgroup dca
32  * @{
33  * @defgroup src
34  * @{
35  **/
36 
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/stat.h>
42 #include <fcntl.h> /* Definition of AT_* constants */
43 #include <unistd.h>
44 #include "safec_lib.h"
45 
46 
47 
48 #define LEN 14
49 #define BUF_LEN 20 // increase the BUF_LEN, because getting the source length is high
50 #define CMD_LEN 256
51 #define MAXLEN 512
52 #define PID_SIZE 10
53 #define PIDOF_SIZE 50
54 #define MEM_STRING_SIZE 20
55 #define PROC_PATH_SIZE 50
56 
57 #include "dcautils.h"
58 
59 /**
60  * @addtogroup DCA_TYPES
61  * @{
62  */
63 #ifdef LIBSYSWRAPPER_BUILD
64 #include "secure_wrapper.h"
65 #endif
66 
67 #define MEM_KEY_PREFIX "mem_"
68 #define CPU_KEY_PREFIX "cpu_"
69 
70 typedef struct proc_info {
71  int utime; /**< User mode jiffies */
72  int stime; /**< Kernel mode jiffies */
73  int cutime; /**< User mode jiffies with childs */
74  int cstime; /**< Kernel mode jiffies with childs */
75  unsigned int rss; /**< Resident Set Size */
76 } procinfo;
77 
78 typedef struct _procMemCpuInfo {
79  pid_t *pid;
80  char processName[BUF_LEN];
81  char cpuUse[BUF_LEN];
82  char memUse[BUF_LEN];
83  int total_instance;
85 
86 /* @} */ // End of group DCA_TYPES
87 
88 
89 int getProcInfo(procMemCpuInfo *pInfo);
90 int getMemInfo(procMemCpuInfo *pmInfo);
91 int getCPUInfo(procMemCpuInfo *pInfo);
92 
93 /**
94  * @addtogroup DCA_APIS
95  * @{
96  */
97 
98 /**
99  * @brief To get process usage.
100  *
101  * @param[in] processName Process name.
102  *
103  * @return Returns status of operation.
104  * @retval 0 on sucess, appropiate errorcode otherwise.
105  */
106 int getProcUsage(char *processName) {
107  if (processName != NULL) {
108  procMemCpuInfo pInfo = { 0 };
109  char pidofCommand[PIDOF_SIZE];
110 #if defined (ENABLE_PS_PROCESS_SEARCH)
111  char psCommand[CMD_LEN];
112 #endif
113  FILE *cmdPid;
114  char *mem_key = NULL, *cpu_key = NULL;
115  int ret = 0;
116  int index = 0;
117  pid_t *pid = NULL;
118  pid_t *temp = NULL;
119  int cpu_key_length = 0, mem_key_length = 0;
120 
121  /*
122  * LIMITATION
123  * Following memcpy() and sprintf() api's can't modified to safec api's
124  * Because, safec has the limitation of copying only 4k ( RSIZE_MAX ) to destination
125  * And here, we have source size more than 4k.
126  */
127  memcpy(pInfo.processName, processName, strlen(processName)+1);
128 
129  sprintf(pidofCommand, "pidof %s", processName);
130 
131 #ifdef LIBSYSWRAPPER_BUILD
132  if (!(cmdPid = v_secure_popen("r", "pidof %s", processName)))
133 #else
134  if (!(cmdPid = popen(pidofCommand, "r")))
135 #endif
136  {
137  LOG("Failed to execute %s", pidofCommand);
138  return 0;
139  }
140 
141  pid = (pid_t *) malloc (sizeof(pid_t));
142  if ( NULL == pid )
143  {
144 #ifdef LIBSYSWRAPPER_BUILD
145  v_secure_pclose(cmdPid);
146 #else
147  pclose(cmdPid);
148 #endif
149  return 0;
150  }
151  *pid=0;
152  while(fscanf(cmdPid,"%d",(pid+index)) == 1)
153  {
154  if ((*(pid+index)) <= 0)
155  {
156  continue;
157  }
158  index++;
159  temp = (pid_t *) realloc (pid,((index+1)*sizeof(pid_t)) );
160  if ( NULL == temp )
161  {
162  free(pid);
163 #ifdef LIBSYSWRAPPER_BUILD
164  v_secure_pclose(cmdPid);
165 #else
166  pclose(cmdPid);
167 #endif
168  return 0;
169  }
170  pid=temp;
171  }
172 
173  #ifdef LIBSYSWRAPPER_BUILD
174  v_secure_pclose(cmdPid);
175  #else
176  pclose(cmdPid);
177  #endif
178 
179 #if defined (ENABLE_PS_PROCESS_SEARCH)
180  // Pidof command output is empty
181  if ((*pid) <= 0)
182  {
183  // pidof was empty, see if we can grab the pid via ps
184  sprintf(psCommand, "busybox ps | grep %s | grep -v grep | awk '{ print $1 }' | tail -n1", processName);
185 
186 #ifdef LIBSYSWRAPPER_BUILD
187  if (!(cmdPid = v_secure_popen("r", "busybox ps | grep %s | grep -v grep | awk '{ print $1 }' | tail -n1", processName)))
188 #else
189  if (!(cmdPid = popen(psCommand, "r")))
190 #endif
191  {
192  return 0;
193  }
194 
195  *pid=0;
196  index=0;
197  while(fscanf(cmdPid,"%d",(pid+index)) == 1)
198  {
199  if ((*(pid+index)) <= 0)
200  {
201  continue;
202  }
203  index++;
204  temp = (pid_t *) realloc (pid,((index+1)*sizeof(pid_t)) );
205  if ( NULL == temp )
206  {
207  free(pid);
208 #ifdef LIBSYSWRAPPER_BUILD
209  v_secure_pclose(cmdPid);
210 #else
211  pclose(cmdPid);
212 #endif
213  return 0;
214  }
215  pid=temp;
216  }
217 
218  #ifdef LIBSYSWRAPPER_BUILD
219  v_secure_pclose(cmdPid);
220  #else
221  pclose(cmdPid);
222  #endif
223 
224  // If pidof command output is empty
225  if ((*pid) <= 0)
226  {
227  free(pid);
228  return 0;
229  }
230  }
231 #else
232  // If pidof command output is empty
233  if ((*pid) <= 0)
234  {
235  free(pid);
236  return 0;
237  }
238 #endif
239 
240  pInfo.total_instance=index;
241  pInfo.pid=pid;
242 
243  if (getProcInfo(&pInfo) == 0) {
244  LOG("Failed to get procInfo for %s", processName);
245  return 0;
246  }
247 
248  mem_key_length = strlen(processName) + strlen(MEM_KEY_PREFIX) + 1;
249  cpu_key_length = strlen(processName) + strlen(CPU_KEY_PREFIX) + 1;
250  mem_key = malloc(mem_key_length);
251  cpu_key = malloc(cpu_key_length);
252  if (NULL != mem_key && NULL != cpu_key)
253  {
254  /*
255  * LIMITATION
256  * Following snprintf() api's can't modified to safec api's
257  * Because, safec has the limitation of copying only 4k ( RSIZE_MAX ) to destination
258  * Here, we have source size more than 4k.
259  */
260  snprintf(cpu_key,cpu_key_length,"%s%s", CPU_KEY_PREFIX,processName);
261 
262  snprintf(mem_key,mem_key_length,"%s%s", MEM_KEY_PREFIX,processName);
263 
264  addToSearchResult(mem_key, pInfo.memUse);
265  addToSearchResult(cpu_key, pInfo.cpuUse);
266  ret = 1;
267  }
268 
269  free(mem_key);
270  free(cpu_key);
271  free(pid);
272 
273  return ret;
274 
275  }
276  return 0;
277 }
278 
279 /**
280  * @brief To get status of a process from its process ID.
281  *
282  * This will return information such as process priority, virtual memory size, signals etc.
283  *
284  * @param[in] pid PID value of the process.
285  * @param[in] pinfo Process info.
286  *
287  * @return Returns status of operation.
288  * @retval Return 1 on success, appropiate errorcode otherwise.
289  */
290 int getProcPidStat(int pid, procinfo * pinfo)
291 {
292  char szFileName [CMD_LEN],szStatStr [2048],*s, *t;
293  //struct stat st;
294  int ppid, pgrp, session, tty, tpgid, counter, priority, starttime, signal, blocked, sigignore, sigcatch,fd, read_len;
295  char exName [CMD_LEN], state;
296  //unsigned euid, egid;
297  unsigned int flags, minflt, cminflt, majflt, cmajflt, timeout, itrealvalue, vsize, rlim, startcode, endcode, startstack, kstkesp, kstkeip, wchan;
298  errno_t rc = -1;
299 
300  if (NULL == pinfo)
301  {
302  LOG("Invalid input(pinfo=NULL) to get process info");
303  return 0;
304  }
305 
306  rc = sprintf_s(szFileName,sizeof(szFileName),"/proc/%u/stat", (unsigned) pid);
307  if(rc < EOK)
308  {
309  ERR_CHK(rc);
310  return 0;
311  }
312 
313  if ((fd = open(szFileName, O_RDONLY)) == -1)
314  {
315  LOG("Unable to access file in get proc info");
316  return 0;
317  }
318 
319 #if 0
320  if(-1 != fstat(fd, &st)) {
321  euid = st.st_uid;
322  egid = st.st_gid;
323  }else {
324  euid = egid = -1;
325  }
326 #endif
327 
328  read_len = read(fd, szStatStr, 2047);
329  if(read_len == -1) {
330  close(fd);
331  return 0;
332  }
333  szStatStr[read_len++] = '\0';
334 
335  /** pid **/
336  s = strchr (szStatStr, '(') + 1;
337  t = strchr (szStatStr, ')');
338 
339  rc = strncpy_s(exName,sizeof(exName),s,t - s);
340  if(rc != EOK)
341  {
342  ERR_CHK(rc);
343  close(fd);
344  return 0;
345  }
346  exName [t - s] = '\0';
347  if(s != NULL && t != NULL && (t-s) > 0){
348  sscanf (t + 2, "%c %d %d %d %d %d %u %u %u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d %d %d %d %u",
349  /* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33*/
350  &(state),
351  &(ppid),
352  &(pgrp),
353  &(session),
354  &(tty),
355  &(tpgid),
356  &(flags),
357  &(minflt),
358  &(cminflt),
359  &(majflt),
360  &(cmajflt),
361  &(pinfo->utime),
362  &(pinfo->stime),
363  &(pinfo->cutime),
364  &(pinfo->cstime),
365  &(counter),
366  &(priority),
367  &(timeout),
368  &(itrealvalue),
369  &(starttime),
370  &(vsize),
371  &(pinfo->rss),
372  &(rlim),
373  &(startcode),
374  &(endcode),
375  &(startstack),
376  &(kstkesp),
377  &(kstkeip),
378  &(signal),
379  &(blocked),
380  &(sigignore),
381  &(sigcatch),
382  &(wchan));
383 }
384  close (fd);
385 
386  return 1;
387 }
388 
389 /**
390  * @brief To get CPU and mem info.
391  *
392  * @param[out] pmInfo Memory/CPU Info.
393  *
394  * @return Returns status of operation.
395  * @retval Return 1 on success.
396  */
398 {
399  if (0 == getMemInfo(pmInfo))
400  return 0;
401 
402  if (0 == getCPUInfo(pmInfo))
403  return 0;
404 
405  return 1;
406 }
407 
408 
409 /**
410  * @brief To get the reserve memory of a given process.
411  *
412  * @param[out] pmInfo Memory Info.
413  *
414  * @return Returns status of operation.
415  * @retval Return 1 on success.
416  */
418 {
419  static char retMem[MEM_STRING_SIZE];
420  int intStr = 0,intValue = 0;
421  double residentMemory = 0.0;
422  procinfo pinfo;
423  long pageSizeInKb = sysconf(_SC_PAGE_SIZE) / 1024; /* x86-64 is configured to use 2MB pages */
424  unsigned int total_memory=0;
425  int index = 0;
426  errno_t rc = -1;
427  int proc_struct_size = sizeof(procinfo);
428  for(index=0;index<(pmInfo->total_instance);index++)
429  {
430  rc = memset_s(&pinfo,proc_struct_size,0,proc_struct_size);
431  ERR_CHK(rc);
432 
433  if( 0 == getProcPidStat(pmInfo->pid[index], &pinfo))
434  return 0;
435  total_memory+=pinfo.rss;
436  }
437 
438  residentMemory = total_memory * pageSizeInKb;
439  intStr = (int)residentMemory;
440  intValue = intStr;
441  if (intValue >= 1024)
442  intStr = intStr/1024;
443  rc = sprintf_s(retMem,sizeof(retMem),"%d%s", intStr,(intValue >= 1024) ? "m" : "k");
444  if(rc < EOK)
445  {
446  ERR_CHK(rc);
447  return 0;
448  }
449 
450  rc = strncpy_s(pmInfo->memUse,sizeof(pmInfo->memUse),retMem,strlen(retMem)+1);
451  if(rc != EOK)
452  {
453  ERR_CHK(rc);
454  return 0;
455  }
456  return 1;
457 }
458 
459 #if !defined(ENABLE_XCAM_SUPPORT) && !defined(ENABLE_RDKB_SUPPORT)
460 /**
461  * @brief To get CPU info.
462  *
463  * @param[out] pInfo CPU info.
464  *
465  * @return Returns status of operation.
466  * @retval Return 1 on success,appropiate errorcode otherwise.
467  */
469 {
470  int ret = 0;
471  FILE *inFp = NULL;
472  char command[CMD_LEN] = {'\0'};
473  char var1[BUF_LEN] = {'\0'};
474  char var2[BUF_LEN] = {'\0'};
475  char var3[BUF_LEN] = {'\0'};
476  char var4[BUF_LEN] = {'\0'};
477  char var5[BUF_LEN] = {'\0'};
478  char var6[BUF_LEN] = {'\0'};
479  char var7[BUF_LEN] = {'\0'};
480  char var8[512]= {'\0'};
481  char var9[512]= {'\0'};
482  char var10[512]= {'\0'};
483  int total_cpu_usage=0;
484  char top_op[2048]= {'\0'};
485  int cmd_option = 0;
486  errno_t rc = -1;
487 
488  if (pInfo == NULL) {
489 
490  return 0;
491  }
492 
493  /* Check Whether -c option is supported */
494  ret = system(" top -c -n 1 2> /dev/null 1> /dev/null");
495  if ( 0 == ret ) {
496  cmd_option = 1;
497  }
498 #ifdef INTEL
499  /* Format Use: `top n 1 | grep Receiver` */
500  if ( 1 == cmd_option ) {
501  rc = sprintf_s(command,sizeof(command),"top -n 1 -c | grep -v grep |grep -i '%s'", pInfo->processName);
502  if(rc < EOK)
503  {
504  ERR_CHK(rc);
505  return 0;
506  }
507  } else {
508  rc = sprintf_s(command,sizeof(command),"top -n 1 | grep -i '%s'", pInfo->processName);
509  if(rc < EOK)
510  {
511  ERR_CHK(rc);
512  return 0;
513  }
514  }
515 
516 #elif AMLOGIC
517  if ( 1 == cmd_option ) {
518  rc = sprintf_s(command,sizeof(command),"COLUMNS=1000 top -b -n 1 -c | grep -v grep | grep -i '%s'", pInfo->processName);
519  if(rc < EOK)
520  {
521  ERR_CHK(rc);
522  return 0;
523  }
524  } else {
525  rc = sprintf_s(command,sizeof(command),"COLUMNS=1000 top -b -n 1 | grep -i '%s'", pInfo->processName);
526  if(rc < EOK)
527  {
528  ERR_CHK(rc);
529  return 0;
530  }
531  }
532 
533 #else
534  /* ps -C Receiver -o %cpu -o %mem */
535  //sprintf(command, "ps -C '%s' -o %%cpu -o %%mem | sed 1d", pInfo->processName);
536  if ( 1 == cmd_option ) {
537  rc = sprintf_s(command,sizeof(command),"top -b -n 1 -c | grep -v grep | grep -i '%s'", pInfo->processName);
538  if(rc < EOK)
539  {
540  ERR_CHK(rc);
541  return 0;
542  }
543  } else {
544  rc = sprintf_s(command,sizeof(command),"top -b -n 1 | grep -i '%s'", pInfo->processName);
545  if(rc < EOK)
546  {
547  ERR_CHK(rc);
548  return 0;
549  }
550  }
551 
552 
553 #endif
554 
555 
556  if(!(inFp = popen(command, "r"))){
557  return 0;
558  }
559 
560 
561  // 2268 root 20 0 831m 66m 20m S 27 13.1 491:06.82 Receiver
562 #ifdef INTEL
563  while(fgets(top_op,2048,inFp)!=NULL) {
564  if(sscanf(top_op,"%s %s %s %s %s %s %s %s", var1, var2, var3, var4, var5, var6, var7, var8) == 8) {
565  total_cpu_usage += atoi(var7);
566  ret=1;
567  }
568  }
569  //#endif
570 #else
571  while(fgets(top_op,2048,inFp)!=NULL) {
572  if(sscanf(top_op,"%16s %16s %16s %16s %16s %16s %16s %512s %512s %512s", var1, var2, var3, var4, var5, var6, var7, var8, var9, var10) == 10) {
573  total_cpu_usage += atoi(var9);
574  ret=1;
575  }
576  }
577 #endif
578 
579  rc = sprintf_s(pInfo->cpuUse,sizeof(pInfo->cpuUse),"%d", total_cpu_usage);
580  if(rc < EOK)
581  {
582  ERR_CHK(rc);
583  pclose(inFp);
584  return 0;
585  }
586  pclose(inFp);
587  return ret;
588 
589 }
590 
591 #else //ENABLE_XCAM_SUPPORT & ENABLE_RDKB_SUPPORT
592 
593 /**
594  * @brief To get total CPU time of the device.
595  *
596  * @param[out] totalTime Total time of device.
597  *
598  * @return Returns status of operation.
599  * @retval Return 1 on success, appropiate errorcode otherwise.
600  */
601 int getTotalCpuTimes(int * totalTime)
602 {
603  FILE *fp;
604  long double a[10];
605  int total;
606 
607  fp = fopen("/proc/stat","r");
608 
609  if(!fp)
610  return 0;
611  /*Coverity Fix CID:109162 CHECKED_RETURN */
612  if(fscanf(fp,"%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf %Lf %Lf %Lf",
613  &a[0],&a[1],&a[2],&a[3],&a[4],&a[5],&a[6],&a[7],&a[8],&a[9]) != 10 )
614  {
615  LOG("Failed in fscanf()\n");
616  }
617 
618  fclose(fp);
619  total = (a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9]);
620  *totalTime = total;
621 
622  return 1;
623 }
624 
625 /**
626  * @brief To get process CPU utilization of the process.
627  *
628  * @param[in] pid Process id.
629  * @param[out] procCpuUtil CPU utilization of process.
630  *
631  * @return Returns status of operation.
632  * @retval Return 1 on success, appropiate errorcode otherwise.
633  */
634 int getProcessCpuUtilization(int pid, float *procCpuUtil)
635 {
636  procinfo pinfo1;
637  //int no_cpu;
638  float total_time_process[2],time[2];
639  int t[2];
640  float sub1;
641  float time1;
642  float util=0;
643 
644 
645  sysconf(_SC_NPROCESSORS_ONLN);
646  if( 0 == getProcPidStat(pid, &pinfo1))
647  return 0;
648 
649  total_time_process[0]= pinfo1.utime +
650  pinfo1.stime +
651  pinfo1.cutime +
652  pinfo1.cstime;
653  //start=pinfo1.starttime;
654 
655  if( !getTotalCpuTimes(&t[0]) )
656  return 0;
657 
658  time[0] = t[0];
659  sleep(2);
660 
661  if( 0 == getProcPidStat(pid,&pinfo1))
662  return 0;
663 
664  total_time_process[1]= pinfo1.utime +
665  pinfo1.stime +
666  pinfo1.cutime +
667  pinfo1.cstime;
668 
669  if( 0 == getTotalCpuTimes(&t[1]) )
670  return 0;
671 
672  time[1] = t[1];
673  sub1 = total_time_process[1]-total_time_process[0];
674  time1= time[1] - time[0];
675  util = (sub1/time1)*100;
676 
677  if(procCpuUtil)
678  *procCpuUtil = util;
679  else
680  return 0;
681 
682  return 1;
683 }
684 
685 
686 int getCPUInfo(procMemCpuInfo *pmInfo) {
687  float cpu = 0;
688  float total_cpu = 0;
689  int index = 0;
690  errno_t rc = -1;
691 
692  for(index=0;index<(pmInfo->total_instance);index++)
693  {
694  if (0 == getProcessCpuUtilization(pmInfo->pid[index], &cpu))
695  {
696  continue;
697  }
698  total_cpu+=cpu;
699  }
700 
701  rc = sprintf_s(pmInfo->cpuUse,sizeof(pmInfo->cpuUse),"%.1f", (float)total_cpu);
702  if(rc < EOK)
703  {
704  ERR_CHK(rc);
705  return 0;
706  }
707  return 1;
708 }
709 
710 #endif //ENABLE_XCAM_SUPPORT & ENABLE_RDKB_SUPPORT
711 
712 /** @} */ //END OF GROUP DCA_APIS
713 
714  /** @} */
715 
716 
717 /** @} */
718 /** @} */
proc_info::stime
int stime
Definition: dcaproc.c:72
_procMemCpuInfo
Definition: dcaproc.c:78
getProcPidStat
int getProcPidStat(int pid, procinfo *pinfo)
To get status of a process from its process ID.
Definition: dcaproc.c:290
proc_info::cstime
int cstime
Definition: dcaproc.c:74
proc_info::cutime
int cutime
Definition: dcaproc.c:73
addToSearchResult
void addToSearchResult(char *key, char *value)
This API is to append the key/value pair to the SearchResult JSON array .
Definition: dcajson.c:71
proc_info::utime
int utime
Definition: dcaproc.c:71
getProcUsage
int getProcUsage(char *processName)
To get process usage.
Definition: dcaproc.c:106
proc_info::rss
unsigned int rss
Definition: dcaproc.c:75
getProcInfo
int getProcInfo(procMemCpuInfo *pInfo)
To get CPU and mem info.
Definition: dcaproc.c:397
proc_info
Definition: dcaproc.c:70
getMemInfo
int getMemInfo(procMemCpuInfo *pmInfo)
To get the reserve memory of a given process.
Definition: dcaproc.c:417
getCPUInfo
int getCPUInfo(procMemCpuInfo *pInfo)
To get CPU info.
Definition: dcaproc.c:468