android_util_Process.cpp revision 0bca96bcbfe559f9330a01f723c5c9cba51ec05a
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 <utils/String8.h>
25#include <utils/Vector.h>
26
27#include <android_runtime/AndroidRuntime.h>
28
29#include "android_util_Binder.h"
30#include "JNIHelp.h"
31
32#include <sys/errno.h>
33#include <sys/resource.h>
34#include <sys/types.h>
35#include <dirent.h>
36#include <fcntl.h>
37#include <grp.h>
38#include <pwd.h>
39#include <signal.h>
40
41/* desktop Linux needs a little help with gettid() */
42#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
43#define __KERNEL__
44# include <linux/unistd.h>
45#ifdef _syscall0
46_syscall0(pid_t,gettid)
47#else
48pid_t gettid() { return syscall(__NR_gettid);}
49#endif
50#undef __KERNEL__
51#endif
52
53/*
54 * List of cgroup names which map to ANDROID_TGROUP_ values in Thread.h
55 * and Process.java
56 * These names are used to construct the path to the cgroup control dir
57 */
58
59static const char *cgroup_names[] = { NULL, "bg_non_interactive", "fg_boost" };
60
61using namespace android;
62
63static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err)
64{
65    switch (err) {
66        case EINVAL:
67            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
68            break;
69        case ESRCH:
70            jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
71            break;
72        case EPERM:
73            jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
74            break;
75        case EACCES:
76            jniThrowException(env, "java/lang/SecurityException", "No permission to set to given priority");
77            break;
78        default:
79            jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
80            break;
81    }
82}
83
84static void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err)
85{
86    switch (err) {
87        case EINVAL:
88            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
89            break;
90        case ESRCH:
91            jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
92            break;
93        case EPERM:
94            jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
95            break;
96        case EACCES:
97            jniThrowException(env, "java/lang/SecurityException", "No permission to set to given group");
98            break;
99        default:
100            jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
101            break;
102    }
103}
104
105
106static void fakeProcessEntry(void* arg)
107{
108    String8* cls = (String8*)arg;
109
110    AndroidRuntime* jr = AndroidRuntime::getRuntime();
111    jr->callMain(cls->string(), 0, NULL);
112
113    delete cls;
114}
115
116jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
117{
118    return getpid();
119}
120
121jint android_os_Process_myUid(JNIEnv* env, jobject clazz)
122{
123    return getuid();
124}
125
126jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
127{
128#ifdef HAVE_GETTID
129    return gettid();
130#else
131    return getpid();
132#endif
133}
134
135jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
136{
137    if (name == NULL) {
138        jniThrowException(env, "java/lang/NullPointerException", NULL);
139        return -1;
140    }
141
142    const jchar* str16 = env->GetStringCritical(name, 0);
143    String8 name8;
144    if (str16) {
145        name8 = String8(str16, 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 passwd* pwd = getpwnam(str);
155                if (pwd == NULL) {
156                    return -1;
157                }
158                return pwd->pw_uid;
159            }
160        }
161        return atoi(str);
162    }
163    return -1;
164}
165
166jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
167{
168    if (name == NULL) {
169        jniThrowException(env, "java/lang/NullPointerException", NULL);
170        return -1;
171    }
172
173    const jchar* str16 = env->GetStringCritical(name, 0);
174    String8 name8;
175    if (str16) {
176        name8 = String8(str16, env->GetStringLength(name));
177        env->ReleaseStringCritical(name, str16);
178    }
179
180    const size_t N = name8.size();
181    if (N > 0) {
182        const char* str = name8.string();
183        for (size_t i=0; i<N; i++) {
184            if (str[i] < '0' || str[i] > '9') {
185                struct group* grp = getgrnam(str);
186                if (grp == NULL) {
187                    return -1;
188                }
189                return grp->gr_gid;
190            }
191        }
192        return atoi(str);
193    }
194    return -1;
195}
196
197static int add_pid_to_cgroup(int pid, int grp)
198{
199    int fd;
200    char path[255];
201    char text[64];
202
203    sprintf(path, "/dev/cpuctl/%s/tasks",
204           (cgroup_names[grp] ? cgroup_names[grp] : ""));
205
206    if ((fd = open(path, O_WRONLY)) < 0)
207        return -1;
208
209    sprintf(text, "%d", pid);
210    if (write(fd, text, strlen(text)) < 0) {
211        close(fd);
212        return -1;
213    }
214
215    close(fd);
216    return 0;
217}
218
219void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
220{
221    if (grp > ANDROID_TGROUP_MAX || grp < 0) {
222        signalExceptionForGroupError(env, clazz, EINVAL);
223        return;
224    }
225
226    if (add_pid_to_cgroup(pid, grp)) {
227        // If the thread exited on us, don't generate an exception
228        if (errno != ESRCH && errno != ENOENT)
229            signalExceptionForGroupError(env, clazz, errno);
230    }
231}
232
233void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
234{
235    DIR *d;
236    FILE *fp;
237    char proc_path[255];
238    struct dirent *de;
239
240    if (grp > ANDROID_TGROUP_MAX || grp < 0) {
241        signalExceptionForGroupError(env, clazz, EINVAL);
242        return;
243    }
244
245    sprintf(proc_path, "/proc/%d/task", pid);
246    if (!(d = opendir(proc_path))) {
247        // If the process exited on us, don't generate an exception
248        if (errno != ENOENT)
249            signalExceptionForGroupError(env, clazz, errno);
250        return;
251    }
252
253    while ((de = readdir(d))) {
254        if (de->d_name[0] == '.')
255            continue;
256
257        if (add_pid_to_cgroup(atoi(de->d_name), grp)) {
258            // If the thread exited on us, ignore it and keep going
259            if (errno != ESRCH && errno != ENOENT) {
260                signalExceptionForGroupError(env, clazz, errno);
261                closedir(d);
262                return;
263            }
264        }
265    }
266    closedir(d);
267}
268
269void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
270                                              jint pid, jint pri)
271{
272    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
273        add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT);
274    } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
275        add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT);
276    }
277
278    if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
279        signalExceptionForPriorityError(env, clazz, errno);
280    }
281    //LOGI("Setting priority of %d: %d, getpriority returns %d\n",
282    //     pid, pri, getpriority(PRIO_PROCESS, pid));
283}
284
285void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
286                                                        jint pri)
287{
288    jint tid = android_os_Process_myTid(env, clazz);
289    android_os_Process_setThreadPriority(env, clazz, tid, pri);
290}
291
292jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
293                                              jint pid)
294{
295    errno = 0;
296    jint pri = getpriority(PRIO_PROCESS, pid);
297    if (errno != 0) {
298        signalExceptionForPriorityError(env, clazz, errno);
299    }
300    //LOGI("Returning priority of %d: %d\n", pid, pri);
301    return pri;
302}
303
304jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
305                                      jint pid, jint adj)
306{
307#ifdef HAVE_OOM_ADJ
308    if (ProcessState::self()->supportsProcesses()) {
309        char text[64];
310        sprintf(text, "/proc/%d/oom_adj", pid);
311        int fd = open(text, O_WRONLY);
312        if (fd >= 0) {
313            sprintf(text, "%d", adj);
314            write(fd, text, strlen(text));
315            close(fd);
316            return true;
317        }
318    }
319#endif
320    return false;
321}
322
323void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
324{
325    if (name == NULL) {
326        jniThrowException(env, "java/lang/NullPointerException", NULL);
327        return;
328    }
329
330    const jchar* str = env->GetStringCritical(name, 0);
331    String8 name8;
332    if (str) {
333        name8 = String8(str, env->GetStringLength(name));
334        env->ReleaseStringCritical(name, str);
335    }
336
337    if (name8.size() > 0) {
338        ProcessState::self()->setArgV0(name8.string());
339    }
340}
341
342jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
343{
344    #if HAVE_ANDROID_OS
345    return setuid(uid) == 0 ? 0 : errno;
346    #else
347    return ENOSYS;
348    #endif
349}
350
351jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
352{
353    #if HAVE_ANDROID_OS
354    return setgid(uid) == 0 ? 0 : errno;
355    #else
356    return ENOSYS;
357    #endif
358}
359
360jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
361{
362    return ProcessState::self()->supportsProcesses();
363}
364
365static int pid_compare(const void* v1, const void* v2)
366{
367    //LOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
368    return *((const jint*)v1) - *((const jint*)v2);
369}
370
371static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
372{
373    int fd = open("/proc/meminfo", O_RDONLY);
374
375    if (fd < 0) {
376        LOGW("Unable to open /proc/meminfo");
377        return -1;
378    }
379
380    char buffer[256];
381    const int len = read(fd, buffer, sizeof(buffer)-1);
382    close(fd);
383
384    if (len < 0) {
385        LOGW("Unable to read /proc/meminfo");
386        return -1;
387    }
388    buffer[len] = 0;
389
390    int numFound = 0;
391    jlong mem = 0;
392
393    static const char* const sums[] = { "MemFree:", "Cached:", NULL };
394    static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
395
396    char* p = buffer;
397    while (*p && numFound < 2) {
398        int i = 0;
399        while (sums[i]) {
400            if (strncmp(p, sums[i], sumsLen[i]) == 0) {
401                p += sumsLen[i];
402                while (*p == ' ') p++;
403                char* num = p;
404                while (*p >= '0' && *p <= '9') p++;
405                if (*p != 0) {
406                    *p = 0;
407                    p++;
408                    if (*p == 0) p--;
409                }
410                mem += atoll(num) * 1024;
411                numFound++;
412                break;
413            }
414            i++;
415        }
416        p++;
417    }
418
419    return numFound > 0 ? mem : -1;
420}
421
422void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr,
423                                      jobjectArray reqFields, jlongArray outFields)
424{
425    //LOGI("getMemInfo: %p %p", reqFields, outFields);
426
427    if (fileStr == NULL || reqFields == NULL || outFields == NULL) {
428        jniThrowException(env, "java/lang/NullPointerException", NULL);
429        return;
430    }
431
432    const char* file8 = env->GetStringUTFChars(fileStr, NULL);
433    if (file8 == NULL) {
434        return;
435    }
436    String8 file(file8);
437    env->ReleaseStringUTFChars(fileStr, file8);
438
439    jsize count = env->GetArrayLength(reqFields);
440    if (count > env->GetArrayLength(outFields)) {
441        jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ");
442        return;
443    }
444
445    Vector<String8> fields;
446    int i;
447
448    for (i=0; i<count; i++) {
449        jobject obj = env->GetObjectArrayElement(reqFields, i);
450        if (obj != NULL) {
451            const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
452            //LOGI("String at %d: %p = %s", i, obj, str8);
453            if (str8 == NULL) {
454                jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
455                return;
456            }
457            fields.add(String8(str8));
458            env->ReleaseStringUTFChars((jstring)obj, str8);
459        } else {
460            jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
461            return;
462        }
463    }
464
465    jlong* sizesArray = env->GetLongArrayElements(outFields, 0);
466    if (sizesArray == NULL) {
467        return;
468    }
469
470    //LOGI("Clearing %d sizes", count);
471    for (i=0; i<count; i++) {
472        sizesArray[i] = 0;
473    }
474
475    int fd = open(file.string(), O_RDONLY);
476
477    if (fd >= 0) {
478        const size_t BUFFER_SIZE = 2048;
479        char* buffer = (char*)malloc(BUFFER_SIZE);
480        int len = read(fd, buffer, BUFFER_SIZE-1);
481        close(fd);
482
483        if (len < 0) {
484            LOGW("Unable to read %s", file.string());
485            len = 0;
486        }
487        buffer[len] = 0;
488
489        int foundCount = 0;
490
491        char* p = buffer;
492        while (*p && foundCount < count) {
493            bool skipToEol = true;
494            //LOGI("Parsing at: %s", p);
495            for (i=0; i<count; i++) {
496                const String8& field = fields[i];
497                if (strncmp(p, field.string(), field.length()) == 0) {
498                    p += field.length();
499                    while (*p == ' ' || *p == '\t') p++;
500                    char* num = p;
501                    while (*p >= '0' && *p <= '9') p++;
502                    skipToEol = *p != '\n';
503                    if (*p != 0) {
504                        *p = 0;
505                        p++;
506                    }
507                    char* end;
508                    sizesArray[i] = strtoll(num, &end, 10);
509                    //LOGI("Field %s = %d", field.string(), sizesArray[i]);
510                    foundCount++;
511                    break;
512                }
513            }
514            if (skipToEol) {
515                while (*p && *p != '\n') {
516                    p++;
517                }
518                if (*p == '\n') {
519                    p++;
520                }
521            }
522        }
523
524        free(buffer);
525    } else {
526        LOGW("Unable to open %s", file.string());
527    }
528
529    //LOGI("Done!");
530    env->ReleaseLongArrayElements(outFields, sizesArray, 0);
531}
532
533jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
534                                     jstring file, jintArray lastArray)
535{
536    if (file == NULL) {
537        jniThrowException(env, "java/lang/NullPointerException", NULL);
538        return NULL;
539    }
540
541    const char* file8 = env->GetStringUTFChars(file, NULL);
542    if (file8 == NULL) {
543        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
544        return NULL;
545    }
546
547    DIR* dirp = opendir(file8);
548
549    env->ReleaseStringUTFChars(file, file8);
550
551    if(dirp == NULL) {
552        return NULL;
553    }
554
555    jsize curCount = 0;
556    jint* curData = NULL;
557    if (lastArray != NULL) {
558        curCount = env->GetArrayLength(lastArray);
559        curData = env->GetIntArrayElements(lastArray, 0);
560    }
561
562    jint curPos = 0;
563
564    struct dirent* entry;
565    while ((entry=readdir(dirp)) != NULL) {
566        const char* p = entry->d_name;
567        while (*p) {
568            if (*p < '0' || *p > '9') break;
569            p++;
570        }
571        if (*p != 0) continue;
572
573        char* end;
574        int pid = strtol(entry->d_name, &end, 10);
575        //LOGI("File %s pid=%d\n", entry->d_name, pid);
576        if (curPos >= curCount) {
577            jsize newCount = (curCount == 0) ? 10 : (curCount*2);
578            jintArray newArray = env->NewIntArray(newCount);
579            if (newArray == NULL) {
580                closedir(dirp);
581                jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
582                return NULL;
583            }
584            jint* newData = env->GetIntArrayElements(newArray, 0);
585            if (curData != NULL) {
586                memcpy(newData, curData, sizeof(jint)*curCount);
587                env->ReleaseIntArrayElements(lastArray, curData, 0);
588            }
589            lastArray = newArray;
590            curCount = newCount;
591            curData = newData;
592        }
593
594        curData[curPos] = pid;
595        curPos++;
596    }
597
598    closedir(dirp);
599
600    if (curData != NULL && curPos > 0) {
601        qsort(curData, curPos, sizeof(jint), pid_compare);
602    }
603
604    while (curPos < curCount) {
605        curData[curPos] = -1;
606        curPos++;
607    }
608
609    if (curData != NULL) {
610        env->ReleaseIntArrayElements(lastArray, curData, 0);
611    }
612
613    return lastArray;
614}
615
616enum {
617    PROC_TERM_MASK = 0xff,
618    PROC_ZERO_TERM = 0,
619    PROC_SPACE_TERM = ' ',
620    PROC_COMBINE = 0x100,
621    PROC_PARENS = 0x200,
622    PROC_OUT_STRING = 0x1000,
623    PROC_OUT_LONG = 0x2000,
624    PROC_OUT_FLOAT = 0x4000,
625};
626
627jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
628        char* buffer, jint startIndex, jint endIndex, jintArray format,
629        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
630{
631
632    const jsize NF = env->GetArrayLength(format);
633    const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
634    const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0;
635    const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0;
636
637    jint* formatData = env->GetIntArrayElements(format, 0);
638    jlong* longsData = outLongs ?
639        env->GetLongArrayElements(outLongs, 0) : NULL;
640    jfloat* floatsData = outFloats ?
641        env->GetFloatArrayElements(outFloats, 0) : NULL;
642    if (formatData == NULL || (NL > 0 && longsData == NULL)
643            || (NR > 0 && floatsData == NULL)) {
644        if (formatData != NULL) {
645            env->ReleaseIntArrayElements(format, formatData, 0);
646        }
647        if (longsData != NULL) {
648            env->ReleaseLongArrayElements(outLongs, longsData, 0);
649        }
650        if (floatsData != NULL) {
651            env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
652        }
653        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
654        return JNI_FALSE;
655    }
656
657    jsize i = startIndex;
658    jsize di = 0;
659
660    jboolean res = JNI_TRUE;
661
662    for (jsize fi=0; fi<NF; fi++) {
663        const jint mode = formatData[fi];
664        if ((mode&PROC_PARENS) != 0) {
665            i++;
666        }
667        const char term = (char)(mode&PROC_TERM_MASK);
668        const jsize start = i;
669        if (i >= endIndex) {
670            res = JNI_FALSE;
671            break;
672        }
673
674        jsize end = -1;
675        if ((mode&PROC_PARENS) != 0) {
676            while (buffer[i] != ')' && i < endIndex) {
677                i++;
678            }
679            end = i;
680            i++;
681        }
682        while (buffer[i] != term && i < endIndex) {
683            i++;
684        }
685        if (end < 0) {
686            end = i;
687        }
688
689        if (i < endIndex) {
690            i++;
691            if ((mode&PROC_COMBINE) != 0) {
692                while (buffer[i] == term && i < endIndex) {
693                    i++;
694                }
695            }
696        }
697
698        //LOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
699
700        if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
701            char c = buffer[end];
702            buffer[end] = 0;
703            if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) {
704                char* end;
705                floatsData[di] = strtof(buffer+start, &end);
706            }
707            if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
708                char* end;
709                longsData[di] = strtoll(buffer+start, &end, 10);
710            }
711            if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
712                jstring str = env->NewStringUTF(buffer+start);
713                env->SetObjectArrayElement(outStrings, di, str);
714            }
715            buffer[end] = c;
716            di++;
717        }
718    }
719
720    env->ReleaseIntArrayElements(format, formatData, 0);
721    if (longsData != NULL) {
722        env->ReleaseLongArrayElements(outLongs, longsData, 0);
723    }
724    if (floatsData != NULL) {
725        env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
726    }
727
728    return res;
729}
730
731jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz,
732        jbyteArray buffer, jint startIndex, jint endIndex, jintArray format,
733        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
734{
735        jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL);
736
737        jboolean result = android_os_Process_parseProcLineArray(env, clazz,
738                (char*) bufferArray, startIndex, endIndex, format, outStrings,
739                outLongs, outFloats);
740
741        env->ReleaseByteArrayElements(buffer, bufferArray, 0);
742
743        return result;
744}
745
746jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
747        jstring file, jintArray format, jobjectArray outStrings,
748        jlongArray outLongs, jfloatArray outFloats)
749{
750    if (file == NULL || format == NULL) {
751        jniThrowException(env, "java/lang/NullPointerException", NULL);
752        return JNI_FALSE;
753    }
754
755    const char* file8 = env->GetStringUTFChars(file, NULL);
756    if (file8 == NULL) {
757        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
758        return JNI_FALSE;
759    }
760    int fd = open(file8, O_RDONLY);
761    env->ReleaseStringUTFChars(file, file8);
762
763    if (fd < 0) {
764        //LOGW("Unable to open process file: %s\n", file8);
765        return JNI_FALSE;
766    }
767
768    char buffer[256];
769    const int len = read(fd, buffer, sizeof(buffer)-1);
770    close(fd);
771
772    if (len < 0) {
773        //LOGW("Unable to open process file: %s fd=%d\n", file8, fd);
774        return JNI_FALSE;
775    }
776    buffer[len] = 0;
777
778    return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len,
779            format, outStrings, outLongs, outFloats);
780
781}
782
783void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
784                                             jobject binderObject)
785{
786    if (binderObject == NULL) {
787        jniThrowException(env, "java/lang/NullPointerException", NULL);
788        return;
789    }
790
791    sp<IBinder> binder = ibinderForJavaObject(env, binderObject);
792}
793
794void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
795{
796    if (pid > 0) {
797        LOGI("Sending signal. PID: %d SIG: %d", pid, sig);
798        kill(pid, sig);
799    }
800}
801
802static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
803{
804    struct timespec ts;
805
806    int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
807
808    if (res != 0) {
809        return (jlong) 0;
810    }
811
812    nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
813    return (jlong) nanoseconds_to_milliseconds(when);
814}
815
816static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
817{
818    char filename[64];
819
820    snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
821
822    FILE * file = fopen(filename, "r");
823    if (!file) {
824        return (jlong) -1;
825    }
826
827    // Tally up all of the Pss from the various maps
828    char line[256];
829    jlong pss = 0;
830    while (fgets(line, sizeof(line), file)) {
831        jlong v;
832        if (sscanf(line, "Pss: %lld kB", &v) == 1) {
833            pss += v;
834        }
835    }
836
837    fclose(file);
838
839    // Return the Pss value in bytes, not kilobytes
840    return pss * 1024;
841}
842
843static const JNINativeMethod methods[] = {
844    {"myPid",       "()I", (void*)android_os_Process_myPid},
845    {"myTid",       "()I", (void*)android_os_Process_myTid},
846    {"myUid",       "()I", (void*)android_os_Process_myUid},
847    {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
848    {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
849    {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
850    {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
851    {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
852    {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
853    {"setProcessGroup",      "(II)V", (void*)android_os_Process_setProcessGroup},
854    {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
855    {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
856    {"setUid", "(I)I", (void*)android_os_Process_setUid},
857    {"setGid", "(I)I", (void*)android_os_Process_setGid},
858    {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
859    {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
860    {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
861    {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
862    {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
863    {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
864    {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
865    {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
866    {"getPss", "(I)J", (void*)android_os_Process_getPss},
867    //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
868};
869
870const char* const kProcessPathName = "android/os/Process";
871
872int register_android_os_Process(JNIEnv* env)
873{
874    jclass clazz;
875
876    clazz = env->FindClass(kProcessPathName);
877    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Process");
878
879    return AndroidRuntime::registerNativeMethods(
880        env, kProcessPathName,
881        methods, NELEM(methods));
882}
883