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