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