android_util_Process.cpp revision d87c19f7d7d7c25638e21d3b8a176b0573369493
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        int t_pid;
255        int t_pri;
256
257        if (de->d_name[0] == '.')
258            continue;
259        t_pid = atoi(de->d_name);
260
261        if (!t_pid) {
262            LOGE("Error getting pid for '%s'\n", de->d_name);
263            continue;
264        }
265
266        t_pri = getpriority(PRIO_PROCESS, t_pid);
267
268        if (grp == ANDROID_TGROUP_DEFAULT &&
269            t_pri >= ANDROID_PRIORITY_BACKGROUND) {
270            // This task wants to stay at background
271            continue;
272        }
273
274        if (add_pid_to_cgroup(t_pid, grp)) {
275            // If the thread exited on us, ignore it and keep going
276            if (errno != ESRCH && errno != ENOENT) {
277                signalExceptionForGroupError(env, clazz, errno);
278                closedir(d);
279                return;
280            }
281        }
282    }
283    closedir(d);
284}
285
286void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
287                                              jint pid, jint pri)
288{
289    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
290        add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT);
291    } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
292        add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT);
293    }
294
295    if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
296        signalExceptionForPriorityError(env, clazz, errno);
297    }
298    //LOGI("Setting priority of %d: %d, getpriority returns %d\n",
299    //     pid, pri, getpriority(PRIO_PROCESS, pid));
300}
301
302void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
303                                                        jint pri)
304{
305    jint tid = android_os_Process_myTid(env, clazz);
306    android_os_Process_setThreadPriority(env, clazz, tid, pri);
307}
308
309jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
310                                              jint pid)
311{
312    errno = 0;
313    jint pri = getpriority(PRIO_PROCESS, pid);
314    if (errno != 0) {
315        signalExceptionForPriorityError(env, clazz, errno);
316    }
317    //LOGI("Returning priority of %d: %d\n", pid, pri);
318    return pri;
319}
320
321jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
322                                      jint pid, jint adj)
323{
324#ifdef HAVE_OOM_ADJ
325    if (ProcessState::self()->supportsProcesses()) {
326        char text[64];
327        sprintf(text, "/proc/%d/oom_adj", pid);
328        int fd = open(text, O_WRONLY);
329        if (fd >= 0) {
330            sprintf(text, "%d", adj);
331            write(fd, text, strlen(text));
332            close(fd);
333            return true;
334        }
335    }
336#endif
337    return false;
338}
339
340void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
341{
342    if (name == NULL) {
343        jniThrowException(env, "java/lang/NullPointerException", NULL);
344        return;
345    }
346
347    const jchar* str = env->GetStringCritical(name, 0);
348    String8 name8;
349    if (str) {
350        name8 = String8(str, env->GetStringLength(name));
351        env->ReleaseStringCritical(name, str);
352    }
353
354    if (name8.size() > 0) {
355        ProcessState::self()->setArgV0(name8.string());
356    }
357}
358
359jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
360{
361    #if HAVE_ANDROID_OS
362    return setuid(uid) == 0 ? 0 : errno;
363    #else
364    return ENOSYS;
365    #endif
366}
367
368jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
369{
370    #if HAVE_ANDROID_OS
371    return setgid(uid) == 0 ? 0 : errno;
372    #else
373    return ENOSYS;
374    #endif
375}
376
377jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
378{
379    return ProcessState::self()->supportsProcesses();
380}
381
382static int pid_compare(const void* v1, const void* v2)
383{
384    //LOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
385    return *((const jint*)v1) - *((const jint*)v2);
386}
387
388static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
389{
390    int fd = open("/proc/meminfo", O_RDONLY);
391
392    if (fd < 0) {
393        LOGW("Unable to open /proc/meminfo");
394        return -1;
395    }
396
397    char buffer[256];
398    const int len = read(fd, buffer, sizeof(buffer)-1);
399    close(fd);
400
401    if (len < 0) {
402        LOGW("Unable to read /proc/meminfo");
403        return -1;
404    }
405    buffer[len] = 0;
406
407    int numFound = 0;
408    jlong mem = 0;
409
410    static const char* const sums[] = { "MemFree:", "Cached:", NULL };
411    static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
412
413    char* p = buffer;
414    while (*p && numFound < 2) {
415        int i = 0;
416        while (sums[i]) {
417            if (strncmp(p, sums[i], sumsLen[i]) == 0) {
418                p += sumsLen[i];
419                while (*p == ' ') p++;
420                char* num = p;
421                while (*p >= '0' && *p <= '9') p++;
422                if (*p != 0) {
423                    *p = 0;
424                    p++;
425                    if (*p == 0) p--;
426                }
427                mem += atoll(num) * 1024;
428                numFound++;
429                break;
430            }
431            i++;
432        }
433        p++;
434    }
435
436    return numFound > 0 ? mem : -1;
437}
438
439void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr,
440                                      jobjectArray reqFields, jlongArray outFields)
441{
442    //LOGI("getMemInfo: %p %p", reqFields, outFields);
443
444    if (fileStr == NULL || reqFields == NULL || outFields == NULL) {
445        jniThrowException(env, "java/lang/NullPointerException", NULL);
446        return;
447    }
448
449    const char* file8 = env->GetStringUTFChars(fileStr, NULL);
450    if (file8 == NULL) {
451        return;
452    }
453    String8 file(file8);
454    env->ReleaseStringUTFChars(fileStr, file8);
455
456    jsize count = env->GetArrayLength(reqFields);
457    if (count > env->GetArrayLength(outFields)) {
458        jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ");
459        return;
460    }
461
462    Vector<String8> fields;
463    int i;
464
465    for (i=0; i<count; i++) {
466        jobject obj = env->GetObjectArrayElement(reqFields, i);
467        if (obj != NULL) {
468            const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
469            //LOGI("String at %d: %p = %s", i, obj, str8);
470            if (str8 == NULL) {
471                jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
472                return;
473            }
474            fields.add(String8(str8));
475            env->ReleaseStringUTFChars((jstring)obj, str8);
476        } else {
477            jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
478            return;
479        }
480    }
481
482    jlong* sizesArray = env->GetLongArrayElements(outFields, 0);
483    if (sizesArray == NULL) {
484        return;
485    }
486
487    //LOGI("Clearing %d sizes", count);
488    for (i=0; i<count; i++) {
489        sizesArray[i] = 0;
490    }
491
492    int fd = open(file.string(), O_RDONLY);
493
494    if (fd >= 0) {
495        const size_t BUFFER_SIZE = 2048;
496        char* buffer = (char*)malloc(BUFFER_SIZE);
497        int len = read(fd, buffer, BUFFER_SIZE-1);
498        close(fd);
499
500        if (len < 0) {
501            LOGW("Unable to read %s", file.string());
502            len = 0;
503        }
504        buffer[len] = 0;
505
506        int foundCount = 0;
507
508        char* p = buffer;
509        while (*p && foundCount < count) {
510            bool skipToEol = true;
511            //LOGI("Parsing at: %s", p);
512            for (i=0; i<count; i++) {
513                const String8& field = fields[i];
514                if (strncmp(p, field.string(), field.length()) == 0) {
515                    p += field.length();
516                    while (*p == ' ' || *p == '\t') p++;
517                    char* num = p;
518                    while (*p >= '0' && *p <= '9') p++;
519                    skipToEol = *p != '\n';
520                    if (*p != 0) {
521                        *p = 0;
522                        p++;
523                    }
524                    char* end;
525                    sizesArray[i] = strtoll(num, &end, 10);
526                    //LOGI("Field %s = %d", field.string(), sizesArray[i]);
527                    foundCount++;
528                    break;
529                }
530            }
531            if (skipToEol) {
532                while (*p && *p != '\n') {
533                    p++;
534                }
535                if (*p == '\n') {
536                    p++;
537                }
538            }
539        }
540
541        free(buffer);
542    } else {
543        LOGW("Unable to open %s", file.string());
544    }
545
546    //LOGI("Done!");
547    env->ReleaseLongArrayElements(outFields, sizesArray, 0);
548}
549
550jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
551                                     jstring file, jintArray lastArray)
552{
553    if (file == NULL) {
554        jniThrowException(env, "java/lang/NullPointerException", NULL);
555        return NULL;
556    }
557
558    const char* file8 = env->GetStringUTFChars(file, NULL);
559    if (file8 == NULL) {
560        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
561        return NULL;
562    }
563
564    DIR* dirp = opendir(file8);
565
566    env->ReleaseStringUTFChars(file, file8);
567
568    if(dirp == NULL) {
569        return NULL;
570    }
571
572    jsize curCount = 0;
573    jint* curData = NULL;
574    if (lastArray != NULL) {
575        curCount = env->GetArrayLength(lastArray);
576        curData = env->GetIntArrayElements(lastArray, 0);
577    }
578
579    jint curPos = 0;
580
581    struct dirent* entry;
582    while ((entry=readdir(dirp)) != NULL) {
583        const char* p = entry->d_name;
584        while (*p) {
585            if (*p < '0' || *p > '9') break;
586            p++;
587        }
588        if (*p != 0) continue;
589
590        char* end;
591        int pid = strtol(entry->d_name, &end, 10);
592        //LOGI("File %s pid=%d\n", entry->d_name, pid);
593        if (curPos >= curCount) {
594            jsize newCount = (curCount == 0) ? 10 : (curCount*2);
595            jintArray newArray = env->NewIntArray(newCount);
596            if (newArray == NULL) {
597                closedir(dirp);
598                jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
599                return NULL;
600            }
601            jint* newData = env->GetIntArrayElements(newArray, 0);
602            if (curData != NULL) {
603                memcpy(newData, curData, sizeof(jint)*curCount);
604                env->ReleaseIntArrayElements(lastArray, curData, 0);
605            }
606            lastArray = newArray;
607            curCount = newCount;
608            curData = newData;
609        }
610
611        curData[curPos] = pid;
612        curPos++;
613    }
614
615    closedir(dirp);
616
617    if (curData != NULL && curPos > 0) {
618        qsort(curData, curPos, sizeof(jint), pid_compare);
619    }
620
621    while (curPos < curCount) {
622        curData[curPos] = -1;
623        curPos++;
624    }
625
626    if (curData != NULL) {
627        env->ReleaseIntArrayElements(lastArray, curData, 0);
628    }
629
630    return lastArray;
631}
632
633enum {
634    PROC_TERM_MASK = 0xff,
635    PROC_ZERO_TERM = 0,
636    PROC_SPACE_TERM = ' ',
637    PROC_COMBINE = 0x100,
638    PROC_PARENS = 0x200,
639    PROC_OUT_STRING = 0x1000,
640    PROC_OUT_LONG = 0x2000,
641    PROC_OUT_FLOAT = 0x4000,
642};
643
644jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
645        char* buffer, jint startIndex, jint endIndex, jintArray format,
646        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
647{
648
649    const jsize NF = env->GetArrayLength(format);
650    const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
651    const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0;
652    const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0;
653
654    jint* formatData = env->GetIntArrayElements(format, 0);
655    jlong* longsData = outLongs ?
656        env->GetLongArrayElements(outLongs, 0) : NULL;
657    jfloat* floatsData = outFloats ?
658        env->GetFloatArrayElements(outFloats, 0) : NULL;
659    if (formatData == NULL || (NL > 0 && longsData == NULL)
660            || (NR > 0 && floatsData == NULL)) {
661        if (formatData != NULL) {
662            env->ReleaseIntArrayElements(format, formatData, 0);
663        }
664        if (longsData != NULL) {
665            env->ReleaseLongArrayElements(outLongs, longsData, 0);
666        }
667        if (floatsData != NULL) {
668            env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
669        }
670        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
671        return JNI_FALSE;
672    }
673
674    jsize i = startIndex;
675    jsize di = 0;
676
677    jboolean res = JNI_TRUE;
678
679    for (jsize fi=0; fi<NF; fi++) {
680        const jint mode = formatData[fi];
681        if ((mode&PROC_PARENS) != 0) {
682            i++;
683        }
684        const char term = (char)(mode&PROC_TERM_MASK);
685        const jsize start = i;
686        if (i >= endIndex) {
687            res = JNI_FALSE;
688            break;
689        }
690
691        jsize end = -1;
692        if ((mode&PROC_PARENS) != 0) {
693            while (buffer[i] != ')' && i < endIndex) {
694                i++;
695            }
696            end = i;
697            i++;
698        }
699        while (buffer[i] != term && i < endIndex) {
700            i++;
701        }
702        if (end < 0) {
703            end = i;
704        }
705
706        if (i < endIndex) {
707            i++;
708            if ((mode&PROC_COMBINE) != 0) {
709                while (buffer[i] == term && i < endIndex) {
710                    i++;
711                }
712            }
713        }
714
715        //LOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
716
717        if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
718            char c = buffer[end];
719            buffer[end] = 0;
720            if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) {
721                char* end;
722                floatsData[di] = strtof(buffer+start, &end);
723            }
724            if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
725                char* end;
726                longsData[di] = strtoll(buffer+start, &end, 10);
727            }
728            if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
729                jstring str = env->NewStringUTF(buffer+start);
730                env->SetObjectArrayElement(outStrings, di, str);
731            }
732            buffer[end] = c;
733            di++;
734        }
735    }
736
737    env->ReleaseIntArrayElements(format, formatData, 0);
738    if (longsData != NULL) {
739        env->ReleaseLongArrayElements(outLongs, longsData, 0);
740    }
741    if (floatsData != NULL) {
742        env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
743    }
744
745    return res;
746}
747
748jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz,
749        jbyteArray buffer, jint startIndex, jint endIndex, jintArray format,
750        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
751{
752        jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL);
753
754        jboolean result = android_os_Process_parseProcLineArray(env, clazz,
755                (char*) bufferArray, startIndex, endIndex, format, outStrings,
756                outLongs, outFloats);
757
758        env->ReleaseByteArrayElements(buffer, bufferArray, 0);
759
760        return result;
761}
762
763jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
764        jstring file, jintArray format, jobjectArray outStrings,
765        jlongArray outLongs, jfloatArray outFloats)
766{
767    if (file == NULL || format == NULL) {
768        jniThrowException(env, "java/lang/NullPointerException", NULL);
769        return JNI_FALSE;
770    }
771
772    const char* file8 = env->GetStringUTFChars(file, NULL);
773    if (file8 == NULL) {
774        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
775        return JNI_FALSE;
776    }
777    int fd = open(file8, O_RDONLY);
778    env->ReleaseStringUTFChars(file, file8);
779
780    if (fd < 0) {
781        //LOGW("Unable to open process file: %s\n", file8);
782        return JNI_FALSE;
783    }
784
785    char buffer[256];
786    const int len = read(fd, buffer, sizeof(buffer)-1);
787    close(fd);
788
789    if (len < 0) {
790        //LOGW("Unable to open process file: %s fd=%d\n", file8, fd);
791        return JNI_FALSE;
792    }
793    buffer[len] = 0;
794
795    return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len,
796            format, outStrings, outLongs, outFloats);
797
798}
799
800void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
801                                             jobject binderObject)
802{
803    if (binderObject == NULL) {
804        jniThrowException(env, "java/lang/NullPointerException", NULL);
805        return;
806    }
807
808    sp<IBinder> binder = ibinderForJavaObject(env, binderObject);
809}
810
811void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
812{
813    if (pid > 0) {
814        LOGI("Sending signal. PID: %d SIG: %d", pid, sig);
815        kill(pid, sig);
816    }
817}
818
819static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
820{
821    struct timespec ts;
822
823    int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
824
825    if (res != 0) {
826        return (jlong) 0;
827    }
828
829    nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
830    return (jlong) nanoseconds_to_milliseconds(when);
831}
832
833static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
834{
835    char filename[64];
836
837    snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
838
839    FILE * file = fopen(filename, "r");
840    if (!file) {
841        return (jlong) -1;
842    }
843
844    // Tally up all of the Pss from the various maps
845    char line[256];
846    jlong pss = 0;
847    while (fgets(line, sizeof(line), file)) {
848        jlong v;
849        if (sscanf(line, "Pss: %lld kB", &v) == 1) {
850            pss += v;
851        }
852    }
853
854    fclose(file);
855
856    // Return the Pss value in bytes, not kilobytes
857    return pss * 1024;
858}
859
860static const JNINativeMethod methods[] = {
861    {"myPid",       "()I", (void*)android_os_Process_myPid},
862    {"myTid",       "()I", (void*)android_os_Process_myTid},
863    {"myUid",       "()I", (void*)android_os_Process_myUid},
864    {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
865    {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
866    {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
867    {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
868    {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
869    {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
870    {"setProcessGroup",      "(II)V", (void*)android_os_Process_setProcessGroup},
871    {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
872    {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
873    {"setUid", "(I)I", (void*)android_os_Process_setUid},
874    {"setGid", "(I)I", (void*)android_os_Process_setGid},
875    {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
876    {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
877    {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
878    {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
879    {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
880    {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
881    {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
882    {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
883    {"getPss", "(I)J", (void*)android_os_Process_getPss},
884    //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
885};
886
887const char* const kProcessPathName = "android/os/Process";
888
889int register_android_os_Process(JNIEnv* env)
890{
891    jclass clazz;
892
893    clazz = env->FindClass(kProcessPathName);
894    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Process");
895
896    return AndroidRuntime::registerNativeMethods(
897        env, kProcessPathName,
898        methods, NELEM(methods));
899}
900