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