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