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