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