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