• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* //device/libs/android_runtime/android_util_Process.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "Process"
19 
20 // To make sure cpu_set_t is included from sched.h
21 #define _GNU_SOURCE 1
22 #include <utils/Log.h>
23 #include <binder/IPCThreadState.h>
24 #include <binder/IServiceManager.h>
25 #include <cutils/process_name.h>
26 #include <cutils/sched_policy.h>
27 #include <utils/String8.h>
28 #include <utils/Vector.h>
29 #include <processgroup/processgroup.h>
30 
31 #include "core_jni_helpers.h"
32 
33 #include "android_util_Binder.h"
34 #include "JNIHelp.h"
35 
36 #include <dirent.h>
37 #include <fcntl.h>
38 #include <grp.h>
39 #include <inttypes.h>
40 #include <pwd.h>
41 #include <signal.h>
42 #include <sys/errno.h>
43 #include <sys/resource.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <unistd.h>
47 
48 #define GUARD_THREAD_PRIORITY 0
49 
50 using namespace android;
51 
52 static const bool kDebugPolicy = false;
53 static const bool kDebugProc = false;
54 
55 #if GUARD_THREAD_PRIORITY
56 Mutex gKeyCreateMutex;
57 static pthread_key_t gBgKey = -1;
58 #endif
59 
60 // For both of these, err should be in the errno range (positive), not a status_t (negative)
signalExceptionForError(JNIEnv * env,int err,int tid)61 static void signalExceptionForError(JNIEnv* env, int err, int tid) {
62     switch (err) {
63         case EINVAL:
64             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
65                                  "Invalid argument: %d", tid);
66             break;
67         case ESRCH:
68             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
69                                  "Given thread %d does not exist", tid);
70             break;
71         case EPERM:
72             jniThrowExceptionFmt(env, "java/lang/SecurityException",
73                                  "No permission to modify given thread %d", tid);
74             break;
75         default:
76             jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
77             break;
78     }
79 }
80 
signalExceptionForPriorityError(JNIEnv * env,int err,int tid)81 static void signalExceptionForPriorityError(JNIEnv* env, int err, int tid) {
82     switch (err) {
83         case EACCES:
84             jniThrowExceptionFmt(env, "java/lang/SecurityException",
85                                  "No permission to set the priority of %d", tid);
86             break;
87         default:
88             signalExceptionForError(env, err, tid);
89             break;
90     }
91 
92 }
93 
signalExceptionForGroupError(JNIEnv * env,int err,int tid)94 static void signalExceptionForGroupError(JNIEnv* env, int err, int tid) {
95     switch (err) {
96         case EACCES:
97             jniThrowExceptionFmt(env, "java/lang/SecurityException",
98                                  "No permission to set the group of %d", tid);
99             break;
100         default:
101             signalExceptionForError(env, err, tid);
102             break;
103     }
104 }
105 
android_os_Process_getUidForName(JNIEnv * env,jobject clazz,jstring name)106 jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
107 {
108     if (name == NULL) {
109         jniThrowNullPointerException(env, NULL);
110         return -1;
111     }
112 
113     const jchar* str16 = env->GetStringCritical(name, 0);
114     String8 name8;
115     if (str16) {
116         name8 = String8(reinterpret_cast<const char16_t*>(str16),
117                         env->GetStringLength(name));
118         env->ReleaseStringCritical(name, str16);
119     }
120 
121     const size_t N = name8.size();
122     if (N > 0) {
123         const char* str = name8.string();
124         for (size_t i=0; i<N; i++) {
125             if (str[i] < '0' || str[i] > '9') {
126                 struct passwd* pwd = getpwnam(str);
127                 if (pwd == NULL) {
128                     return -1;
129                 }
130                 return pwd->pw_uid;
131             }
132         }
133         return atoi(str);
134     }
135     return -1;
136 }
137 
android_os_Process_getGidForName(JNIEnv * env,jobject clazz,jstring name)138 jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
139 {
140     if (name == NULL) {
141         jniThrowNullPointerException(env, NULL);
142         return -1;
143     }
144 
145     const jchar* str16 = env->GetStringCritical(name, 0);
146     String8 name8;
147     if (str16) {
148         name8 = String8(reinterpret_cast<const char16_t*>(str16),
149                         env->GetStringLength(name));
150         env->ReleaseStringCritical(name, str16);
151     }
152 
153     const size_t N = name8.size();
154     if (N > 0) {
155         const char* str = name8.string();
156         for (size_t i=0; i<N; i++) {
157             if (str[i] < '0' || str[i] > '9') {
158                 struct group* grp = getgrnam(str);
159                 if (grp == NULL) {
160                     return -1;
161                 }
162                 return grp->gr_gid;
163             }
164         }
165         return atoi(str);
166     }
167     return -1;
168 }
169 
android_os_Process_setThreadGroup(JNIEnv * env,jobject clazz,int tid,jint grp)170 void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint grp)
171 {
172     ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp);
173     SchedPolicy sp = (SchedPolicy) grp;
174     int res = set_sched_policy(tid, sp);
175     if (res != NO_ERROR) {
176         signalExceptionForGroupError(env, -res, tid);
177     }
178 }
179 
android_os_Process_setProcessGroup(JNIEnv * env,jobject clazz,int pid,jint grp)180 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
181 {
182     ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
183     DIR *d;
184     char proc_path[255];
185     struct dirent *de;
186 
187     if ((grp == SP_FOREGROUND) || (grp > SP_MAX)) {
188         signalExceptionForGroupError(env, EINVAL, pid);
189         return;
190     }
191 
192     bool isDefault = false;
193     if (grp < 0) {
194         grp = SP_FOREGROUND;
195         isDefault = true;
196     }
197     SchedPolicy sp = (SchedPolicy) grp;
198 
199     if (kDebugPolicy) {
200         char cmdline[32];
201         int fd;
202 
203         strcpy(cmdline, "unknown");
204 
205         sprintf(proc_path, "/proc/%d/cmdline", pid);
206         fd = open(proc_path, O_RDONLY);
207         if (fd >= 0) {
208             int rc = read(fd, cmdline, sizeof(cmdline)-1);
209             cmdline[rc] = 0;
210             close(fd);
211         }
212 
213         if (sp == SP_BACKGROUND) {
214             ALOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline);
215         } else {
216             ALOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline);
217         }
218     }
219 
220     sprintf(proc_path, "/proc/%d/task", pid);
221     if (!(d = opendir(proc_path))) {
222         // If the process exited on us, don't generate an exception
223         if (errno != ENOENT)
224             signalExceptionForGroupError(env, errno, pid);
225         return;
226     }
227 
228     while ((de = readdir(d))) {
229         int t_pid;
230         int t_pri;
231 
232         if (de->d_name[0] == '.')
233             continue;
234         t_pid = atoi(de->d_name);
235 
236         if (!t_pid) {
237             ALOGE("Error getting pid for '%s'\n", de->d_name);
238             continue;
239         }
240 
241         t_pri = getpriority(PRIO_PROCESS, t_pid);
242 
243         if (t_pri <= ANDROID_PRIORITY_AUDIO) {
244             int scheduler = sched_getscheduler(t_pid) & ~SCHED_RESET_ON_FORK;
245             if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
246                 // This task wants to stay in its current audio group so it can keep its budget
247                 // don't update its cpuset or cgroup
248                 continue;
249             }
250         }
251 
252         if (isDefault) {
253             if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
254                 // This task wants to stay at background
255                 // update its cpuset so it doesn't only run on bg core(s)
256 #ifdef ENABLE_CPUSETS
257                 int err = set_cpuset_policy(t_pid, sp);
258                 if (err != NO_ERROR) {
259                     signalExceptionForGroupError(env, -err, t_pid);
260                     break;
261                 }
262 #endif
263                 continue;
264             }
265         }
266         int err;
267 #ifdef ENABLE_CPUSETS
268         // set both cpuset and cgroup for general threads
269         err = set_cpuset_policy(t_pid, sp);
270         if (err != NO_ERROR) {
271             signalExceptionForGroupError(env, -err, t_pid);
272             break;
273         }
274 #endif
275 
276         err = set_sched_policy(t_pid, sp);
277         if (err != NO_ERROR) {
278             signalExceptionForGroupError(env, -err, t_pid);
279             break;
280         }
281 
282     }
283     closedir(d);
284 }
285 
android_os_Process_getProcessGroup(JNIEnv * env,jobject clazz,jint pid)286 jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
287 {
288     SchedPolicy sp;
289     if (get_sched_policy(pid, &sp) != 0) {
290         signalExceptionForGroupError(env, errno, pid);
291     }
292     return (int) sp;
293 }
294 
295 #ifdef ENABLE_CPUSETS
296 /** Sample CPUset list format:
297  *  0-3,4,6-8
298  */
parse_cpuset_cpus(char * cpus,cpu_set_t * cpu_set)299 static void parse_cpuset_cpus(char *cpus, cpu_set_t *cpu_set) {
300     unsigned int start, end, matched, i;
301     char *cpu_range = strtok(cpus, ",");
302     while (cpu_range != NULL) {
303         start = end = 0;
304         matched = sscanf(cpu_range, "%u-%u", &start, &end);
305         cpu_range = strtok(NULL, ",");
306         if (start >= CPU_SETSIZE) {
307             ALOGE("parse_cpuset_cpus: ignoring CPU number larger than %d.", CPU_SETSIZE);
308             continue;
309         } else if (end >= CPU_SETSIZE) {
310             ALOGE("parse_cpuset_cpus: ignoring CPU numbers larger than %d.", CPU_SETSIZE);
311             end = CPU_SETSIZE - 1;
312         }
313         if (matched == 1) {
314             CPU_SET(start, cpu_set);
315         } else if (matched == 2) {
316             for (i = start; i <= end; i++) {
317                 CPU_SET(i, cpu_set);
318             }
319         } else {
320             ALOGE("Failed to match cpus");
321         }
322     }
323     return;
324 }
325 
326 /**
327  * Stores the CPUs assigned to the cpuset corresponding to the
328  * SchedPolicy in the passed in cpu_set.
329  */
get_cpuset_cores_for_policy(SchedPolicy policy,cpu_set_t * cpu_set)330 static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set)
331 {
332     FILE *file;
333     const char *filename;
334 
335     CPU_ZERO(cpu_set);
336 
337     switch (policy) {
338         case SP_BACKGROUND:
339             filename = "/dev/cpuset/background/cpus";
340             break;
341         case SP_FOREGROUND:
342         case SP_AUDIO_APP:
343         case SP_AUDIO_SYS:
344             filename = "/dev/cpuset/foreground/cpus";
345             break;
346         case SP_TOP_APP:
347             filename = "/dev/cpuset/top-app/cpus";
348             break;
349         default:
350             filename = NULL;
351     }
352 
353     if (!filename) return;
354 
355     file = fopen(filename, "re");
356     if (file != NULL) {
357         // Parse cpus string
358         char *line = NULL;
359         size_t len = 0;
360         ssize_t num_read = getline(&line, &len, file);
361         fclose (file);
362         if (num_read > 0) {
363             parse_cpuset_cpus(line, cpu_set);
364         } else {
365             ALOGE("Failed to read %s", filename);
366         }
367         free(line);
368     }
369     return;
370 }
371 #endif
372 
373 
374 /**
375  * Determine CPU cores exclusively assigned to the
376  * cpuset corresponding to the SchedPolicy and store
377  * them in the passed in cpu_set_t
378  */
get_exclusive_cpuset_cores(SchedPolicy policy,cpu_set_t * cpu_set)379 void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) {
380 #ifdef ENABLE_CPUSETS
381     int i;
382     cpu_set_t tmp_set;
383     get_cpuset_cores_for_policy(policy, cpu_set);
384     for (i = 0; i < SP_CNT; i++) {
385         if ((SchedPolicy) i == policy) continue;
386         get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
387         // First get cores exclusive to one set or the other
388         CPU_XOR(&tmp_set, cpu_set, &tmp_set);
389         // Then get the ones only in cpu_set
390         CPU_AND(cpu_set, cpu_set, &tmp_set);
391     }
392 #else
393     (void) policy;
394     CPU_ZERO(cpu_set);
395 #endif
396     return;
397 }
398 
android_os_Process_getExclusiveCores(JNIEnv * env,jobject clazz)399 jintArray android_os_Process_getExclusiveCores(JNIEnv* env, jobject clazz) {
400     SchedPolicy sp;
401     cpu_set_t cpu_set;
402     jintArray cpus;
403     int pid = getpid();
404     if (get_sched_policy(pid, &sp) != 0) {
405         signalExceptionForGroupError(env, errno, pid);
406         return NULL;
407     }
408     get_exclusive_cpuset_cores(sp, &cpu_set);
409     int num_cpus = CPU_COUNT(&cpu_set);
410     cpus = env->NewIntArray(num_cpus);
411     if (cpus == NULL) {
412         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
413         return NULL;
414     }
415 
416     jint* cpu_elements = env->GetIntArrayElements(cpus, 0);
417     int count = 0;
418     for (int i = 0; i < CPU_SETSIZE && count < num_cpus; i++) {
419         if (CPU_ISSET(i, &cpu_set)) {
420             cpu_elements[count++] = i;
421         }
422     }
423 
424     env->ReleaseIntArrayElements(cpus, cpu_elements, 0);
425     return cpus;
426 }
427 
android_os_Process_setCanSelfBackground(JNIEnv * env,jobject clazz,jboolean bgOk)428 static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) {
429     // Establishes the calling thread as illegal to put into the background.
430     // Typically used only for the system process's main looper.
431 #if GUARD_THREAD_PRIORITY
432     ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid());
433     {
434         Mutex::Autolock _l(gKeyCreateMutex);
435         if (gBgKey == -1) {
436             pthread_key_create(&gBgKey, NULL);
437         }
438     }
439 
440     // inverted:  not-okay, we set a sentinel value
441     pthread_setspecific(gBgKey, (void*)(bgOk ? 0 : 0xbaad));
442 #endif
443 }
444 
android_os_Process_getThreadScheduler(JNIEnv * env,jclass clazz,jint tid)445 jint android_os_Process_getThreadScheduler(JNIEnv* env, jclass clazz,
446                                               jint tid)
447 {
448     int policy = 0;
449 // linux has sched_getscheduler(), others don't.
450 #if defined(__linux__)
451     errno = 0;
452     policy = sched_getscheduler(tid);
453     if (errno != 0) {
454         signalExceptionForPriorityError(env, errno, tid);
455     }
456 #else
457     signalExceptionForPriorityError(env, ENOSYS, tid);
458 #endif
459     return policy;
460 }
461 
android_os_Process_setThreadScheduler(JNIEnv * env,jclass clazz,jint tid,jint policy,jint pri)462 void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz,
463                                               jint tid, jint policy, jint pri)
464 {
465 // linux has sched_setscheduler(), others don't.
466 #if defined(__linux__)
467     struct sched_param param;
468     param.sched_priority = pri;
469     int rc = sched_setscheduler(tid, policy, &param);
470     if (rc) {
471         signalExceptionForPriorityError(env, errno, tid);
472     }
473 #else
474     signalExceptionForPriorityError(env, ENOSYS, tid);
475 #endif
476 }
477 
android_os_Process_setThreadPriority(JNIEnv * env,jobject clazz,jint pid,jint pri)478 void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
479                                               jint pid, jint pri)
480 {
481 #if GUARD_THREAD_PRIORITY
482     // if we're putting the current thread into the background, check the TLS
483     // to make sure this thread isn't guarded.  If it is, raise an exception.
484     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
485         if (pid == gettid()) {
486             void* bgOk = pthread_getspecific(gBgKey);
487             if (bgOk == ((void*)0xbaad)) {
488                 ALOGE("Thread marked fg-only put self in background!");
489                 jniThrowException(env, "java/lang/SecurityException", "May not put this thread into background");
490                 return;
491             }
492         }
493     }
494 #endif
495 
496     int rc = androidSetThreadPriority(pid, pri);
497     if (rc != 0) {
498         if (rc == INVALID_OPERATION) {
499             signalExceptionForPriorityError(env, errno, pid);
500         } else {
501             signalExceptionForGroupError(env, errno, pid);
502         }
503     }
504 
505     //ALOGI("Setting priority of %" PRId32 ": %" PRId32 ", getpriority returns %d\n",
506     //     pid, pri, getpriority(PRIO_PROCESS, pid));
507 }
508 
android_os_Process_setCallingThreadPriority(JNIEnv * env,jobject clazz,jint pri)509 void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
510                                                         jint pri)
511 {
512     android_os_Process_setThreadPriority(env, clazz, gettid(), pri);
513 }
514 
android_os_Process_getThreadPriority(JNIEnv * env,jobject clazz,jint pid)515 jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
516                                               jint pid)
517 {
518     errno = 0;
519     jint pri = getpriority(PRIO_PROCESS, pid);
520     if (errno != 0) {
521         signalExceptionForPriorityError(env, errno, pid);
522     }
523     //ALOGI("Returning priority of %" PRId32 ": %" PRId32 "\n", pid, pri);
524     return pri;
525 }
526 
android_os_Process_setSwappiness(JNIEnv * env,jobject clazz,jint pid,jboolean is_increased)527 jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
528                                           jint pid, jboolean is_increased)
529 {
530     char text[64];
531 
532     if (is_increased) {
533         strcpy(text, "/sys/fs/cgroup/memory/sw/tasks");
534     } else {
535         strcpy(text, "/sys/fs/cgroup/memory/tasks");
536     }
537 
538     struct stat st;
539     if (stat(text, &st) || !S_ISREG(st.st_mode)) {
540         return false;
541     }
542 
543     int fd = open(text, O_WRONLY);
544     if (fd >= 0) {
545         sprintf(text, "%" PRId32, pid);
546         write(fd, text, strlen(text));
547         close(fd);
548     }
549 
550     return true;
551 }
552 
android_os_Process_setArgV0(JNIEnv * env,jobject clazz,jstring name)553 void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
554 {
555     if (name == NULL) {
556         jniThrowNullPointerException(env, NULL);
557         return;
558     }
559 
560     const jchar* str = env->GetStringCritical(name, 0);
561     String8 name8;
562     if (str) {
563         name8 = String8(reinterpret_cast<const char16_t*>(str),
564                         env->GetStringLength(name));
565         env->ReleaseStringCritical(name, str);
566     }
567 
568     if (name8.size() > 0) {
569         const char* procName = name8.string();
570         set_process_name(procName);
571         AndroidRuntime::getRuntime()->setArgv0(procName);
572     }
573 }
574 
android_os_Process_setUid(JNIEnv * env,jobject clazz,jint uid)575 jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
576 {
577     return setuid(uid) == 0 ? 0 : errno;
578 }
579 
android_os_Process_setGid(JNIEnv * env,jobject clazz,jint uid)580 jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
581 {
582     return setgid(uid) == 0 ? 0 : errno;
583 }
584 
pid_compare(const void * v1,const void * v2)585 static int pid_compare(const void* v1, const void* v2)
586 {
587     //ALOGI("Compare %" PRId32 " vs %" PRId32 "\n", *((const jint*)v1), *((const jint*)v2));
588     return *((const jint*)v1) - *((const jint*)v2);
589 }
590 
getFreeMemoryImpl(const char * const sums[],const size_t sumsLen[],size_t num)591 static jlong getFreeMemoryImpl(const char* const sums[], const size_t sumsLen[], size_t num)
592 {
593     int fd = open("/proc/meminfo", O_RDONLY);
594 
595     if (fd < 0) {
596         ALOGW("Unable to open /proc/meminfo");
597         return -1;
598     }
599 
600     char buffer[256];
601     const int len = read(fd, buffer, sizeof(buffer)-1);
602     close(fd);
603 
604     if (len < 0) {
605         ALOGW("Unable to read /proc/meminfo");
606         return -1;
607     }
608     buffer[len] = 0;
609 
610     size_t numFound = 0;
611     jlong mem = 0;
612 
613     char* p = buffer;
614     while (*p && numFound < num) {
615         int i = 0;
616         while (sums[i]) {
617             if (strncmp(p, sums[i], sumsLen[i]) == 0) {
618                 p += sumsLen[i];
619                 while (*p == ' ') p++;
620                 char* num = p;
621                 while (*p >= '0' && *p <= '9') p++;
622                 if (*p != 0) {
623                     *p = 0;
624                     p++;
625                     if (*p == 0) p--;
626                 }
627                 mem += atoll(num) * 1024;
628                 numFound++;
629                 break;
630             }
631             i++;
632         }
633         p++;
634     }
635 
636     return numFound > 0 ? mem : -1;
637 }
638 
android_os_Process_getFreeMemory(JNIEnv * env,jobject clazz)639 static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
640 {
641     static const char* const sums[] = { "MemFree:", "Cached:", NULL };
642     static const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 };
643     return getFreeMemoryImpl(sums, sumsLen, 2);
644 }
645 
android_os_Process_getTotalMemory(JNIEnv * env,jobject clazz)646 static jlong android_os_Process_getTotalMemory(JNIEnv* env, jobject clazz)
647 {
648     static const char* const sums[] = { "MemTotal:", NULL };
649     static const size_t sumsLen[] = { strlen("MemTotal:"), 0 };
650     return getFreeMemoryImpl(sums, sumsLen, 1);
651 }
652 
android_os_Process_readProcLines(JNIEnv * env,jobject clazz,jstring fileStr,jobjectArray reqFields,jlongArray outFields)653 void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr,
654                                       jobjectArray reqFields, jlongArray outFields)
655 {
656     //ALOGI("getMemInfo: %p %p", reqFields, outFields);
657 
658     if (fileStr == NULL || reqFields == NULL || outFields == NULL) {
659         jniThrowNullPointerException(env, NULL);
660         return;
661     }
662 
663     const char* file8 = env->GetStringUTFChars(fileStr, NULL);
664     if (file8 == NULL) {
665         return;
666     }
667     String8 file(file8);
668     env->ReleaseStringUTFChars(fileStr, file8);
669 
670     jsize count = env->GetArrayLength(reqFields);
671     if (count > env->GetArrayLength(outFields)) {
672         jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ");
673         return;
674     }
675 
676     Vector<String8> fields;
677     int i;
678 
679     for (i=0; i<count; i++) {
680         jobject obj = env->GetObjectArrayElement(reqFields, i);
681         if (obj != NULL) {
682             const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
683             //ALOGI("String at %d: %p = %s", i, obj, str8);
684             if (str8 == NULL) {
685                 jniThrowNullPointerException(env, "Element in reqFields");
686                 return;
687             }
688             fields.add(String8(str8));
689             env->ReleaseStringUTFChars((jstring)obj, str8);
690         } else {
691             jniThrowNullPointerException(env, "Element in reqFields");
692             return;
693         }
694     }
695 
696     jlong* sizesArray = env->GetLongArrayElements(outFields, 0);
697     if (sizesArray == NULL) {
698         return;
699     }
700 
701     //ALOGI("Clearing %" PRId32 " sizes", count);
702     for (i=0; i<count; i++) {
703         sizesArray[i] = 0;
704     }
705 
706     int fd = open(file.string(), O_RDONLY);
707 
708     if (fd >= 0) {
709         const size_t BUFFER_SIZE = 2048;
710         char* buffer = (char*)malloc(BUFFER_SIZE);
711         int len = read(fd, buffer, BUFFER_SIZE-1);
712         close(fd);
713 
714         if (len < 0) {
715             ALOGW("Unable to read %s", file.string());
716             len = 0;
717         }
718         buffer[len] = 0;
719 
720         int foundCount = 0;
721 
722         char* p = buffer;
723         while (*p && foundCount < count) {
724             bool skipToEol = true;
725             //ALOGI("Parsing at: %s", p);
726             for (i=0; i<count; i++) {
727                 const String8& field = fields[i];
728                 if (strncmp(p, field.string(), field.length()) == 0) {
729                     p += field.length();
730                     while (*p == ' ' || *p == '\t') p++;
731                     char* num = p;
732                     while (*p >= '0' && *p <= '9') p++;
733                     skipToEol = *p != '\n';
734                     if (*p != 0) {
735                         *p = 0;
736                         p++;
737                     }
738                     char* end;
739                     sizesArray[i] = strtoll(num, &end, 10);
740                     //ALOGI("Field %s = %" PRId64, field.string(), sizesArray[i]);
741                     foundCount++;
742                     break;
743                 }
744             }
745             if (skipToEol) {
746                 while (*p && *p != '\n') {
747                     p++;
748                 }
749                 if (*p == '\n') {
750                     p++;
751                 }
752             }
753         }
754 
755         free(buffer);
756     } else {
757         ALOGW("Unable to open %s", file.string());
758     }
759 
760     //ALOGI("Done!");
761     env->ReleaseLongArrayElements(outFields, sizesArray, 0);
762 }
763 
android_os_Process_getPids(JNIEnv * env,jobject clazz,jstring file,jintArray lastArray)764 jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
765                                      jstring file, jintArray lastArray)
766 {
767     if (file == NULL) {
768         jniThrowNullPointerException(env, NULL);
769         return NULL;
770     }
771 
772     const char* file8 = env->GetStringUTFChars(file, NULL);
773     if (file8 == NULL) {
774         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
775         return NULL;
776     }
777 
778     DIR* dirp = opendir(file8);
779 
780     env->ReleaseStringUTFChars(file, file8);
781 
782     if(dirp == NULL) {
783         return NULL;
784     }
785 
786     jsize curCount = 0;
787     jint* curData = NULL;
788     if (lastArray != NULL) {
789         curCount = env->GetArrayLength(lastArray);
790         curData = env->GetIntArrayElements(lastArray, 0);
791     }
792 
793     jint curPos = 0;
794 
795     struct dirent* entry;
796     while ((entry=readdir(dirp)) != NULL) {
797         const char* p = entry->d_name;
798         while (*p) {
799             if (*p < '0' || *p > '9') break;
800             p++;
801         }
802         if (*p != 0) continue;
803 
804         char* end;
805         int pid = strtol(entry->d_name, &end, 10);
806         //ALOGI("File %s pid=%d\n", entry->d_name, pid);
807         if (curPos >= curCount) {
808             jsize newCount = (curCount == 0) ? 10 : (curCount*2);
809             jintArray newArray = env->NewIntArray(newCount);
810             if (newArray == NULL) {
811                 closedir(dirp);
812                 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
813                 return NULL;
814             }
815             jint* newData = env->GetIntArrayElements(newArray, 0);
816             if (curData != NULL) {
817                 memcpy(newData, curData, sizeof(jint)*curCount);
818                 env->ReleaseIntArrayElements(lastArray, curData, 0);
819             }
820             lastArray = newArray;
821             curCount = newCount;
822             curData = newData;
823         }
824 
825         curData[curPos] = pid;
826         curPos++;
827     }
828 
829     closedir(dirp);
830 
831     if (curData != NULL && curPos > 0) {
832         qsort(curData, curPos, sizeof(jint), pid_compare);
833     }
834 
835     while (curPos < curCount) {
836         curData[curPos] = -1;
837         curPos++;
838     }
839 
840     if (curData != NULL) {
841         env->ReleaseIntArrayElements(lastArray, curData, 0);
842     }
843 
844     return lastArray;
845 }
846 
847 enum {
848     PROC_TERM_MASK = 0xff,
849     PROC_ZERO_TERM = 0,
850     PROC_SPACE_TERM = ' ',
851     PROC_COMBINE = 0x100,
852     PROC_PARENS = 0x200,
853     PROC_QUOTES = 0x400,
854     PROC_CHAR = 0x800,
855     PROC_OUT_STRING = 0x1000,
856     PROC_OUT_LONG = 0x2000,
857     PROC_OUT_FLOAT = 0x4000,
858 };
859 
android_os_Process_parseProcLineArray(JNIEnv * env,jobject clazz,char * buffer,jint startIndex,jint endIndex,jintArray format,jobjectArray outStrings,jlongArray outLongs,jfloatArray outFloats)860 jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
861         char* buffer, jint startIndex, jint endIndex, jintArray format,
862         jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
863 {
864 
865     const jsize NF = env->GetArrayLength(format);
866     const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
867     const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0;
868     const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0;
869 
870     jint* formatData = env->GetIntArrayElements(format, 0);
871     jlong* longsData = outLongs ?
872         env->GetLongArrayElements(outLongs, 0) : NULL;
873     jfloat* floatsData = outFloats ?
874         env->GetFloatArrayElements(outFloats, 0) : NULL;
875     if (formatData == NULL || (NL > 0 && longsData == NULL)
876             || (NR > 0 && floatsData == NULL)) {
877         if (formatData != NULL) {
878             env->ReleaseIntArrayElements(format, formatData, 0);
879         }
880         if (longsData != NULL) {
881             env->ReleaseLongArrayElements(outLongs, longsData, 0);
882         }
883         if (floatsData != NULL) {
884             env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
885         }
886         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
887         return JNI_FALSE;
888     }
889 
890     jsize i = startIndex;
891     jsize di = 0;
892 
893     jboolean res = JNI_TRUE;
894 
895     for (jsize fi=0; fi<NF; fi++) {
896         jint mode = formatData[fi];
897         if ((mode&PROC_PARENS) != 0) {
898             i++;
899         } else if ((mode&PROC_QUOTES) != 0) {
900             if (buffer[i] == '"') {
901                 i++;
902             } else {
903                 mode &= ~PROC_QUOTES;
904             }
905         }
906         const char term = (char)(mode&PROC_TERM_MASK);
907         const jsize start = i;
908         if (i >= endIndex) {
909             if (kDebugProc) {
910                 ALOGW("Ran off end of data @%d", i);
911             }
912             res = JNI_FALSE;
913             break;
914         }
915 
916         jsize end = -1;
917         if ((mode&PROC_PARENS) != 0) {
918             while (i < endIndex && buffer[i] != ')') {
919                 i++;
920             }
921             end = i;
922             i++;
923         } else if ((mode&PROC_QUOTES) != 0) {
924             while (buffer[i] != '"' && i < endIndex) {
925                 i++;
926             }
927             end = i;
928             i++;
929         }
930         while (i < endIndex && buffer[i] != term) {
931             i++;
932         }
933         if (end < 0) {
934             end = i;
935         }
936 
937         if (i < endIndex) {
938             i++;
939             if ((mode&PROC_COMBINE) != 0) {
940                 while (i < endIndex && buffer[i] == term) {
941                     i++;
942                 }
943             }
944         }
945 
946         //ALOGI("Field %" PRId32 ": %" PRId32 "-%" PRId32 " dest=%" PRId32 " mode=0x%" PRIx32 "\n", i, start, end, di, mode);
947 
948         if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
949             char c = buffer[end];
950             buffer[end] = 0;
951             if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) {
952                 char* end;
953                 floatsData[di] = strtof(buffer+start, &end);
954             }
955             if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
956                 if ((mode&PROC_CHAR) != 0) {
957                     // Caller wants single first character returned as one long.
958                     longsData[di] = buffer[start];
959                 } else {
960                     char* end;
961                     longsData[di] = strtoll(buffer+start, &end, 10);
962                 }
963             }
964             if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
965                 jstring str = env->NewStringUTF(buffer+start);
966                 env->SetObjectArrayElement(outStrings, di, str);
967             }
968             buffer[end] = c;
969             di++;
970         }
971     }
972 
973     env->ReleaseIntArrayElements(format, formatData, 0);
974     if (longsData != NULL) {
975         env->ReleaseLongArrayElements(outLongs, longsData, 0);
976     }
977     if (floatsData != NULL) {
978         env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
979     }
980 
981     return res;
982 }
983 
android_os_Process_parseProcLine(JNIEnv * env,jobject clazz,jbyteArray buffer,jint startIndex,jint endIndex,jintArray format,jobjectArray outStrings,jlongArray outLongs,jfloatArray outFloats)984 jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz,
985         jbyteArray buffer, jint startIndex, jint endIndex, jintArray format,
986         jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
987 {
988         jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL);
989 
990         jboolean result = android_os_Process_parseProcLineArray(env, clazz,
991                 (char*) bufferArray, startIndex, endIndex, format, outStrings,
992                 outLongs, outFloats);
993 
994         env->ReleaseByteArrayElements(buffer, bufferArray, 0);
995 
996         return result;
997 }
998 
android_os_Process_readProcFile(JNIEnv * env,jobject clazz,jstring file,jintArray format,jobjectArray outStrings,jlongArray outLongs,jfloatArray outFloats)999 jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
1000         jstring file, jintArray format, jobjectArray outStrings,
1001         jlongArray outLongs, jfloatArray outFloats)
1002 {
1003     if (file == NULL || format == NULL) {
1004         jniThrowNullPointerException(env, NULL);
1005         return JNI_FALSE;
1006     }
1007 
1008     const char* file8 = env->GetStringUTFChars(file, NULL);
1009     if (file8 == NULL) {
1010         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1011         return JNI_FALSE;
1012     }
1013     int fd = open(file8, O_RDONLY);
1014 
1015     if (fd < 0) {
1016         if (kDebugProc) {
1017             ALOGW("Unable to open process file: %s\n", file8);
1018         }
1019         env->ReleaseStringUTFChars(file, file8);
1020         return JNI_FALSE;
1021     }
1022     env->ReleaseStringUTFChars(file, file8);
1023 
1024     char buffer[256];
1025     const int len = read(fd, buffer, sizeof(buffer)-1);
1026     close(fd);
1027 
1028     if (len < 0) {
1029         if (kDebugProc) {
1030             ALOGW("Unable to open process file: %s fd=%d\n", file8, fd);
1031         }
1032         return JNI_FALSE;
1033     }
1034     buffer[len] = 0;
1035 
1036     return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len,
1037             format, outStrings, outLongs, outFloats);
1038 
1039 }
1040 
android_os_Process_setApplicationObject(JNIEnv * env,jobject clazz,jobject binderObject)1041 void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
1042                                              jobject binderObject)
1043 {
1044     if (binderObject == NULL) {
1045         jniThrowNullPointerException(env, NULL);
1046         return;
1047     }
1048 
1049     sp<IBinder> binder = ibinderForJavaObject(env, binderObject);
1050 }
1051 
android_os_Process_sendSignal(JNIEnv * env,jobject clazz,jint pid,jint sig)1052 void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
1053 {
1054     if (pid > 0) {
1055         ALOGI("Sending signal. PID: %" PRId32 " SIG: %" PRId32, pid, sig);
1056         kill(pid, sig);
1057     }
1058 }
1059 
android_os_Process_sendSignalQuiet(JNIEnv * env,jobject clazz,jint pid,jint sig)1060 void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig)
1061 {
1062     if (pid > 0) {
1063         kill(pid, sig);
1064     }
1065 }
1066 
android_os_Process_getElapsedCpuTime(JNIEnv * env,jobject clazz)1067 static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
1068 {
1069     struct timespec ts;
1070 
1071     int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
1072 
1073     if (res != 0) {
1074         return (jlong) 0;
1075     }
1076 
1077     nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
1078     return (jlong) nanoseconds_to_milliseconds(when);
1079 }
1080 
android_os_Process_getPss(JNIEnv * env,jobject clazz,jint pid)1081 static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
1082 {
1083     char filename[64];
1084 
1085     snprintf(filename, sizeof(filename), "/proc/%" PRId32 "/smaps", pid);
1086 
1087     FILE * file = fopen(filename, "r");
1088     if (!file) {
1089         return (jlong) -1;
1090     }
1091 
1092     // Tally up all of the Pss from the various maps
1093     char line[256];
1094     jlong pss = 0;
1095     while (fgets(line, sizeof(line), file)) {
1096         jlong v;
1097         if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) {
1098             pss += v;
1099         }
1100     }
1101 
1102     fclose(file);
1103 
1104     // Return the Pss value in bytes, not kilobytes
1105     return pss * 1024;
1106 }
1107 
android_os_Process_getPidsForCommands(JNIEnv * env,jobject clazz,jobjectArray commandNames)1108 jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz,
1109         jobjectArray commandNames)
1110 {
1111     if (commandNames == NULL) {
1112         jniThrowNullPointerException(env, NULL);
1113         return NULL;
1114     }
1115 
1116     Vector<String8> commands;
1117 
1118     jsize count = env->GetArrayLength(commandNames);
1119 
1120     for (int i=0; i<count; i++) {
1121         jobject obj = env->GetObjectArrayElement(commandNames, i);
1122         if (obj != NULL) {
1123             const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
1124             if (str8 == NULL) {
1125                 jniThrowNullPointerException(env, "Element in commandNames");
1126                 return NULL;
1127             }
1128             commands.add(String8(str8));
1129             env->ReleaseStringUTFChars((jstring)obj, str8);
1130         } else {
1131             jniThrowNullPointerException(env, "Element in commandNames");
1132             return NULL;
1133         }
1134     }
1135 
1136     Vector<jint> pids;
1137 
1138     DIR *proc = opendir("/proc");
1139     if (proc == NULL) {
1140         fprintf(stderr, "/proc: %s\n", strerror(errno));
1141         return NULL;
1142     }
1143 
1144     struct dirent *d;
1145     while ((d = readdir(proc))) {
1146         int pid = atoi(d->d_name);
1147         if (pid <= 0) continue;
1148 
1149         char path[PATH_MAX];
1150         char data[PATH_MAX];
1151         snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
1152 
1153         int fd = open(path, O_RDONLY);
1154         if (fd < 0) {
1155             continue;
1156         }
1157         const int len = read(fd, data, sizeof(data)-1);
1158         close(fd);
1159 
1160         if (len < 0) {
1161             continue;
1162         }
1163         data[len] = 0;
1164 
1165         for (int i=0; i<len; i++) {
1166             if (data[i] == ' ') {
1167                 data[i] = 0;
1168                 break;
1169             }
1170         }
1171 
1172         for (size_t i=0; i<commands.size(); i++) {
1173             if (commands[i] == data) {
1174                 pids.add(pid);
1175                 break;
1176             }
1177         }
1178     }
1179 
1180     closedir(proc);
1181 
1182     jintArray pidArray = env->NewIntArray(pids.size());
1183     if (pidArray == NULL) {
1184         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1185         return NULL;
1186     }
1187 
1188     if (pids.size() > 0) {
1189         env->SetIntArrayRegion(pidArray, 0, pids.size(), pids.array());
1190     }
1191 
1192     return pidArray;
1193 }
1194 
android_os_Process_killProcessGroup(JNIEnv * env,jobject clazz,jint uid,jint pid)1195 jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid)
1196 {
1197     return killProcessGroup(uid, pid, SIGKILL);
1198 }
1199 
android_os_Process_removeAllProcessGroups(JNIEnv * env,jobject clazz)1200 void android_os_Process_removeAllProcessGroups(JNIEnv* env, jobject clazz)
1201 {
1202     return removeAllProcessGroups();
1203 }
1204 
1205 static const JNINativeMethod methods[] = {
1206     {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
1207     {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
1208     {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
1209     {"setThreadScheduler",  "(III)V", (void*)android_os_Process_setThreadScheduler},
1210     {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
1211     {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
1212     {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
1213     {"getThreadScheduler",   "(I)I", (void*)android_os_Process_getThreadScheduler},
1214     {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
1215     {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},
1216     {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},
1217     {"getExclusiveCores",   "()[I", (void*)android_os_Process_getExclusiveCores},
1218     {"setSwappiness",   "(IZ)Z", (void*)android_os_Process_setSwappiness},
1219     {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
1220     {"setUid", "(I)I", (void*)android_os_Process_setUid},
1221     {"setGid", "(I)I", (void*)android_os_Process_setGid},
1222     {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
1223     {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
1224     {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
1225     {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
1226     {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
1227     {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
1228     {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
1229     {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
1230     {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
1231     {"getPss", "(I)J", (void*)android_os_Process_getPss},
1232     {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands},
1233     //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
1234     {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
1235     {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
1236 };
1237 
register_android_os_Process(JNIEnv * env)1238 int register_android_os_Process(JNIEnv* env)
1239 {
1240     return RegisterMethodsOrDie(env, "android/os/Process", methods, NELEM(methods));
1241 }
1242