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