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