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