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