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