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