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