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