android_util_Process.cpp revision 9e41c7479ccaedb89a89a58079570ca0ee0e3727
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/IServiceManager.h> 23#include <cutils/process_name.h> 24#include <cutils/sched_policy.h> 25#include <utils/String8.h> 26#include <utils/Vector.h> 27#include <processgroup/processgroup.h> 28 29#include "core_jni_helpers.h" 30 31#include "android_util_Binder.h" 32#include "JNIHelp.h" 33 34#include <dirent.h> 35#include <fcntl.h> 36#include <grp.h> 37#include <inttypes.h> 38#include <pwd.h> 39#include <signal.h> 40#include <sys/errno.h> 41#include <sys/resource.h> 42#include <sys/stat.h> 43#include <sys/types.h> 44#include <unistd.h> 45 46#define GUARD_THREAD_PRIORITY 0 47 48using namespace android; 49 50static const bool kDebugPolicy = false; 51static const bool kDebugProc = false; 52 53#if GUARD_THREAD_PRIORITY 54Mutex gKeyCreateMutex; 55static pthread_key_t gBgKey = -1; 56#endif 57 58// For both of these, err should be in the errno range (positive), not a status_t (negative) 59 60static void signalExceptionForPriorityError(JNIEnv* env, int err) 61{ 62 switch (err) { 63 case EINVAL: 64 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 65 break; 66 case ESRCH: 67 jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist"); 68 break; 69 case EPERM: 70 jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread"); 71 break; 72 case EACCES: 73 jniThrowException(env, "java/lang/SecurityException", "No permission to set to given priority"); 74 break; 75 default: 76 jniThrowException(env, "java/lang/RuntimeException", "Unknown error"); 77 break; 78 } 79} 80 81static void signalExceptionForGroupError(JNIEnv* env, int err) 82{ 83 switch (err) { 84 case EINVAL: 85 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 86 break; 87 case ESRCH: 88 jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist"); 89 break; 90 case EPERM: 91 jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread"); 92 break; 93 case EACCES: 94 jniThrowException(env, "java/lang/SecurityException", "No permission to set to given group"); 95 break; 96 default: 97 jniThrowException(env, "java/lang/RuntimeException", "Unknown error"); 98 break; 99 } 100} 101 102jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name) 103{ 104 if (name == NULL) { 105 jniThrowNullPointerException(env, NULL); 106 return -1; 107 } 108 109 const jchar* str16 = env->GetStringCritical(name, 0); 110 String8 name8; 111 if (str16) { 112 name8 = String8(reinterpret_cast<const char16_t*>(str16), 113 env->GetStringLength(name)); 114 env->ReleaseStringCritical(name, str16); 115 } 116 117 const size_t N = name8.size(); 118 if (N > 0) { 119 const char* str = name8.string(); 120 for (size_t i=0; i<N; i++) { 121 if (str[i] < '0' || str[i] > '9') { 122 struct passwd* pwd = getpwnam(str); 123 if (pwd == NULL) { 124 return -1; 125 } 126 return pwd->pw_uid; 127 } 128 } 129 return atoi(str); 130 } 131 return -1; 132} 133 134jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name) 135{ 136 if (name == NULL) { 137 jniThrowNullPointerException(env, NULL); 138 return -1; 139 } 140 141 const jchar* str16 = env->GetStringCritical(name, 0); 142 String8 name8; 143 if (str16) { 144 name8 = String8(reinterpret_cast<const char16_t*>(str16), 145 env->GetStringLength(name)); 146 env->ReleaseStringCritical(name, str16); 147 } 148 149 const size_t N = name8.size(); 150 if (N > 0) { 151 const char* str = name8.string(); 152 for (size_t i=0; i<N; i++) { 153 if (str[i] < '0' || str[i] > '9') { 154 struct group* grp = getgrnam(str); 155 if (grp == NULL) { 156 return -1; 157 } 158 return grp->gr_gid; 159 } 160 } 161 return atoi(str); 162 } 163 return -1; 164} 165 166void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint grp) 167{ 168 ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp); 169 SchedPolicy sp = (SchedPolicy) grp; 170 int res = set_sched_policy(tid, sp); 171 if (res != NO_ERROR) { 172 signalExceptionForGroupError(env, -res); 173 } 174} 175 176void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp) 177{ 178 ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp); 179 DIR *d; 180 char proc_path[255]; 181 struct dirent *de; 182 183 if ((grp == SP_FOREGROUND) || (grp > SP_MAX)) { 184 signalExceptionForGroupError(env, EINVAL); 185 return; 186 } 187 188 bool isDefault = false; 189 if (grp < 0) { 190 grp = SP_FOREGROUND; 191 isDefault = true; 192 } 193 SchedPolicy sp = (SchedPolicy) grp; 194 195 if (kDebugPolicy) { 196 char cmdline[32]; 197 int fd; 198 199 strcpy(cmdline, "unknown"); 200 201 sprintf(proc_path, "/proc/%d/cmdline", pid); 202 fd = open(proc_path, O_RDONLY); 203 if (fd >= 0) { 204 int rc = read(fd, cmdline, sizeof(cmdline)-1); 205 cmdline[rc] = 0; 206 close(fd); 207 } 208 209 if (sp == SP_BACKGROUND) { 210 ALOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline); 211 } else { 212 ALOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline); 213 } 214 } 215 216 sprintf(proc_path, "/proc/%d/task", pid); 217 if (!(d = opendir(proc_path))) { 218 // If the process exited on us, don't generate an exception 219 if (errno != ENOENT) 220 signalExceptionForGroupError(env, errno); 221 return; 222 } 223 224 while ((de = readdir(d))) { 225 int t_pid; 226 int t_pri; 227 228 if (de->d_name[0] == '.') 229 continue; 230 t_pid = atoi(de->d_name); 231 232 if (!t_pid) { 233 ALOGE("Error getting pid for '%s'\n", de->d_name); 234 continue; 235 } 236 237 t_pri = getpriority(PRIO_PROCESS, t_pid); 238 239 if (t_pri <= ANDROID_PRIORITY_AUDIO) { 240 int scheduler = sched_getscheduler(t_pid); 241 if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) { 242 // This task wants to stay in its current audio group so it can keep its budget 243 // don't update its cpuset or cgroup 244 continue; 245 } 246 } 247 248 if (isDefault) { 249 if (t_pri >= ANDROID_PRIORITY_BACKGROUND) { 250 // This task wants to stay at background 251 // update its cpuset so it doesn't only run on bg core(s) 252#ifdef ENABLE_CPUSETS 253 int err = set_cpuset_policy(t_pid, sp); 254 if (err != NO_ERROR) { 255 signalExceptionForGroupError(env, -err); 256 break; 257 } 258#endif 259 continue; 260 } 261 } 262 int err; 263#ifdef ENABLE_CPUSETS 264 // set both cpuset and cgroup for general threads 265 err = set_cpuset_policy(t_pid, sp); 266 if (err != NO_ERROR) { 267 signalExceptionForGroupError(env, -err); 268 break; 269 } 270#endif 271 272 err = set_sched_policy(t_pid, sp); 273 if (err != NO_ERROR) { 274 signalExceptionForGroupError(env, -err); 275 break; 276 } 277 278 } 279 closedir(d); 280} 281 282jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid) 283{ 284 SchedPolicy sp; 285 if (get_sched_policy(pid, &sp) != 0) { 286 signalExceptionForGroupError(env, errno); 287 } 288 return (int) sp; 289} 290 291static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) { 292 // Establishes the calling thread as illegal to put into the background. 293 // Typically used only for the system process's main looper. 294#if GUARD_THREAD_PRIORITY 295 ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid()); 296 { 297 Mutex::Autolock _l(gKeyCreateMutex); 298 if (gBgKey == -1) { 299 pthread_key_create(&gBgKey, NULL); 300 } 301 } 302 303 // inverted: not-okay, we set a sentinel value 304 pthread_setspecific(gBgKey, (void*)(bgOk ? 0 : 0xbaad)); 305#endif 306} 307 308void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz, 309 jint tid, jint policy, jint pri) 310{ 311// linux has sched_setscheduler(), others don't. 312#if defined(__linux__) 313 struct sched_param param; 314 param.sched_priority = pri; 315 int rc = sched_setscheduler(tid, policy, ¶m); 316 if (rc) { 317 signalExceptionForPriorityError(env, errno); 318 } 319#else 320 signalExceptionForPriorityError(env, ENOSYS); 321#endif 322} 323 324void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, 325 jint pid, jint pri) 326{ 327#if GUARD_THREAD_PRIORITY 328 // if we're putting the current thread into the background, check the TLS 329 // to make sure this thread isn't guarded. If it is, raise an exception. 330 if (pri >= ANDROID_PRIORITY_BACKGROUND) { 331 if (pid == gettid()) { 332 void* bgOk = pthread_getspecific(gBgKey); 333 if (bgOk == ((void*)0xbaad)) { 334 ALOGE("Thread marked fg-only put self in background!"); 335 jniThrowException(env, "java/lang/SecurityException", "May not put this thread into background"); 336 return; 337 } 338 } 339 } 340#endif 341 342 int rc = androidSetThreadPriority(pid, pri); 343 if (rc != 0) { 344 if (rc == INVALID_OPERATION) { 345 signalExceptionForPriorityError(env, errno); 346 } else { 347 signalExceptionForGroupError(env, errno); 348 } 349 } 350 351 //ALOGI("Setting priority of %" PRId32 ": %" PRId32 ", getpriority returns %d\n", 352 // pid, pri, getpriority(PRIO_PROCESS, pid)); 353} 354 355void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz, 356 jint pri) 357{ 358 android_os_Process_setThreadPriority(env, clazz, gettid(), pri); 359} 360 361jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz, 362 jint pid) 363{ 364 errno = 0; 365 jint pri = getpriority(PRIO_PROCESS, pid); 366 if (errno != 0) { 367 signalExceptionForPriorityError(env, errno); 368 } 369 //ALOGI("Returning priority of %" PRId32 ": %" PRId32 "\n", pid, pri); 370 return pri; 371} 372 373jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz, 374 jint pid, jboolean is_increased) 375{ 376 char text[64]; 377 378 if (is_increased) { 379 strcpy(text, "/sys/fs/cgroup/memory/sw/tasks"); 380 } else { 381 strcpy(text, "/sys/fs/cgroup/memory/tasks"); 382 } 383 384 struct stat st; 385 if (stat(text, &st) || !S_ISREG(st.st_mode)) { 386 return false; 387 } 388 389 int fd = open(text, O_WRONLY); 390 if (fd >= 0) { 391 sprintf(text, "%" PRId32, pid); 392 write(fd, text, strlen(text)); 393 close(fd); 394 } 395 396 return true; 397} 398 399void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name) 400{ 401 if (name == NULL) { 402 jniThrowNullPointerException(env, NULL); 403 return; 404 } 405 406 const jchar* str = env->GetStringCritical(name, 0); 407 String8 name8; 408 if (str) { 409 name8 = String8(reinterpret_cast<const char16_t*>(str), 410 env->GetStringLength(name)); 411 env->ReleaseStringCritical(name, str); 412 } 413 414 if (name8.size() > 0) { 415 const char* procName = name8.string(); 416 set_process_name(procName); 417 AndroidRuntime::getRuntime()->setArgv0(procName); 418 } 419} 420 421jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid) 422{ 423 return setuid(uid) == 0 ? 0 : errno; 424} 425 426jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid) 427{ 428 return setgid(uid) == 0 ? 0 : errno; 429} 430 431static int pid_compare(const void* v1, const void* v2) 432{ 433 //ALOGI("Compare %" PRId32 " vs %" PRId32 "\n", *((const jint*)v1), *((const jint*)v2)); 434 return *((const jint*)v1) - *((const jint*)v2); 435} 436 437static jlong getFreeMemoryImpl(const char* const sums[], const size_t sumsLen[], size_t num) 438{ 439 int fd = open("/proc/meminfo", O_RDONLY); 440 441 if (fd < 0) { 442 ALOGW("Unable to open /proc/meminfo"); 443 return -1; 444 } 445 446 char buffer[256]; 447 const int len = read(fd, buffer, sizeof(buffer)-1); 448 close(fd); 449 450 if (len < 0) { 451 ALOGW("Unable to read /proc/meminfo"); 452 return -1; 453 } 454 buffer[len] = 0; 455 456 size_t numFound = 0; 457 jlong mem = 0; 458 459 char* p = buffer; 460 while (*p && numFound < num) { 461 int i = 0; 462 while (sums[i]) { 463 if (strncmp(p, sums[i], sumsLen[i]) == 0) { 464 p += sumsLen[i]; 465 while (*p == ' ') p++; 466 char* num = p; 467 while (*p >= '0' && *p <= '9') p++; 468 if (*p != 0) { 469 *p = 0; 470 p++; 471 if (*p == 0) p--; 472 } 473 mem += atoll(num) * 1024; 474 numFound++; 475 break; 476 } 477 i++; 478 } 479 p++; 480 } 481 482 return numFound > 0 ? mem : -1; 483} 484 485static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz) 486{ 487 static const char* const sums[] = { "MemFree:", "Cached:", NULL }; 488 static const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 }; 489 return getFreeMemoryImpl(sums, sumsLen, 2); 490} 491 492static jlong android_os_Process_getTotalMemory(JNIEnv* env, jobject clazz) 493{ 494 static const char* const sums[] = { "MemTotal:", NULL }; 495 static const size_t sumsLen[] = { strlen("MemTotal:"), 0 }; 496 return getFreeMemoryImpl(sums, sumsLen, 1); 497} 498 499void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr, 500 jobjectArray reqFields, jlongArray outFields) 501{ 502 //ALOGI("getMemInfo: %p %p", reqFields, outFields); 503 504 if (fileStr == NULL || reqFields == NULL || outFields == NULL) { 505 jniThrowNullPointerException(env, NULL); 506 return; 507 } 508 509 const char* file8 = env->GetStringUTFChars(fileStr, NULL); 510 if (file8 == NULL) { 511 return; 512 } 513 String8 file(file8); 514 env->ReleaseStringUTFChars(fileStr, file8); 515 516 jsize count = env->GetArrayLength(reqFields); 517 if (count > env->GetArrayLength(outFields)) { 518 jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ"); 519 return; 520 } 521 522 Vector<String8> fields; 523 int i; 524 525 for (i=0; i<count; i++) { 526 jobject obj = env->GetObjectArrayElement(reqFields, i); 527 if (obj != NULL) { 528 const char* str8 = env->GetStringUTFChars((jstring)obj, NULL); 529 //ALOGI("String at %d: %p = %s", i, obj, str8); 530 if (str8 == NULL) { 531 jniThrowNullPointerException(env, "Element in reqFields"); 532 return; 533 } 534 fields.add(String8(str8)); 535 env->ReleaseStringUTFChars((jstring)obj, str8); 536 } else { 537 jniThrowNullPointerException(env, "Element in reqFields"); 538 return; 539 } 540 } 541 542 jlong* sizesArray = env->GetLongArrayElements(outFields, 0); 543 if (sizesArray == NULL) { 544 return; 545 } 546 547 //ALOGI("Clearing %" PRId32 " sizes", count); 548 for (i=0; i<count; i++) { 549 sizesArray[i] = 0; 550 } 551 552 int fd = open(file.string(), O_RDONLY); 553 554 if (fd >= 0) { 555 const size_t BUFFER_SIZE = 2048; 556 char* buffer = (char*)malloc(BUFFER_SIZE); 557 int len = read(fd, buffer, BUFFER_SIZE-1); 558 close(fd); 559 560 if (len < 0) { 561 ALOGW("Unable to read %s", file.string()); 562 len = 0; 563 } 564 buffer[len] = 0; 565 566 int foundCount = 0; 567 568 char* p = buffer; 569 while (*p && foundCount < count) { 570 bool skipToEol = true; 571 //ALOGI("Parsing at: %s", p); 572 for (i=0; i<count; i++) { 573 const String8& field = fields[i]; 574 if (strncmp(p, field.string(), field.length()) == 0) { 575 p += field.length(); 576 while (*p == ' ' || *p == '\t') p++; 577 char* num = p; 578 while (*p >= '0' && *p <= '9') p++; 579 skipToEol = *p != '\n'; 580 if (*p != 0) { 581 *p = 0; 582 p++; 583 } 584 char* end; 585 sizesArray[i] = strtoll(num, &end, 10); 586 //ALOGI("Field %s = %" PRId64, field.string(), sizesArray[i]); 587 foundCount++; 588 break; 589 } 590 } 591 if (skipToEol) { 592 while (*p && *p != '\n') { 593 p++; 594 } 595 if (*p == '\n') { 596 p++; 597 } 598 } 599 } 600 601 free(buffer); 602 } else { 603 ALOGW("Unable to open %s", file.string()); 604 } 605 606 //ALOGI("Done!"); 607 env->ReleaseLongArrayElements(outFields, sizesArray, 0); 608} 609 610jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz, 611 jstring file, jintArray lastArray) 612{ 613 if (file == NULL) { 614 jniThrowNullPointerException(env, NULL); 615 return NULL; 616 } 617 618 const char* file8 = env->GetStringUTFChars(file, NULL); 619 if (file8 == NULL) { 620 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 621 return NULL; 622 } 623 624 DIR* dirp = opendir(file8); 625 626 env->ReleaseStringUTFChars(file, file8); 627 628 if(dirp == NULL) { 629 return NULL; 630 } 631 632 jsize curCount = 0; 633 jint* curData = NULL; 634 if (lastArray != NULL) { 635 curCount = env->GetArrayLength(lastArray); 636 curData = env->GetIntArrayElements(lastArray, 0); 637 } 638 639 jint curPos = 0; 640 641 struct dirent* entry; 642 while ((entry=readdir(dirp)) != NULL) { 643 const char* p = entry->d_name; 644 while (*p) { 645 if (*p < '0' || *p > '9') break; 646 p++; 647 } 648 if (*p != 0) continue; 649 650 char* end; 651 int pid = strtol(entry->d_name, &end, 10); 652 //ALOGI("File %s pid=%d\n", entry->d_name, pid); 653 if (curPos >= curCount) { 654 jsize newCount = (curCount == 0) ? 10 : (curCount*2); 655 jintArray newArray = env->NewIntArray(newCount); 656 if (newArray == NULL) { 657 closedir(dirp); 658 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 659 return NULL; 660 } 661 jint* newData = env->GetIntArrayElements(newArray, 0); 662 if (curData != NULL) { 663 memcpy(newData, curData, sizeof(jint)*curCount); 664 env->ReleaseIntArrayElements(lastArray, curData, 0); 665 } 666 lastArray = newArray; 667 curCount = newCount; 668 curData = newData; 669 } 670 671 curData[curPos] = pid; 672 curPos++; 673 } 674 675 closedir(dirp); 676 677 if (curData != NULL && curPos > 0) { 678 qsort(curData, curPos, sizeof(jint), pid_compare); 679 } 680 681 while (curPos < curCount) { 682 curData[curPos] = -1; 683 curPos++; 684 } 685 686 if (curData != NULL) { 687 env->ReleaseIntArrayElements(lastArray, curData, 0); 688 } 689 690 return lastArray; 691} 692 693enum { 694 PROC_TERM_MASK = 0xff, 695 PROC_ZERO_TERM = 0, 696 PROC_SPACE_TERM = ' ', 697 PROC_COMBINE = 0x100, 698 PROC_PARENS = 0x200, 699 PROC_QUOTES = 0x400, 700 PROC_OUT_STRING = 0x1000, 701 PROC_OUT_LONG = 0x2000, 702 PROC_OUT_FLOAT = 0x4000, 703}; 704 705jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, 706 char* buffer, jint startIndex, jint endIndex, jintArray format, 707 jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) 708{ 709 710 const jsize NF = env->GetArrayLength(format); 711 const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0; 712 const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0; 713 const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0; 714 715 jint* formatData = env->GetIntArrayElements(format, 0); 716 jlong* longsData = outLongs ? 717 env->GetLongArrayElements(outLongs, 0) : NULL; 718 jfloat* floatsData = outFloats ? 719 env->GetFloatArrayElements(outFloats, 0) : NULL; 720 if (formatData == NULL || (NL > 0 && longsData == NULL) 721 || (NR > 0 && floatsData == NULL)) { 722 if (formatData != NULL) { 723 env->ReleaseIntArrayElements(format, formatData, 0); 724 } 725 if (longsData != NULL) { 726 env->ReleaseLongArrayElements(outLongs, longsData, 0); 727 } 728 if (floatsData != NULL) { 729 env->ReleaseFloatArrayElements(outFloats, floatsData, 0); 730 } 731 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 732 return JNI_FALSE; 733 } 734 735 jsize i = startIndex; 736 jsize di = 0; 737 738 jboolean res = JNI_TRUE; 739 740 for (jsize fi=0; fi<NF; fi++) { 741 jint mode = formatData[fi]; 742 if ((mode&PROC_PARENS) != 0) { 743 i++; 744 } else if ((mode&PROC_QUOTES) != 0) { 745 if (buffer[i] == '"') { 746 i++; 747 } else { 748 mode &= ~PROC_QUOTES; 749 } 750 } 751 const char term = (char)(mode&PROC_TERM_MASK); 752 const jsize start = i; 753 if (i >= endIndex) { 754 if (kDebugProc) { 755 ALOGW("Ran off end of data @%d", i); 756 } 757 res = JNI_FALSE; 758 break; 759 } 760 761 jsize end = -1; 762 if ((mode&PROC_PARENS) != 0) { 763 while (i < endIndex && buffer[i] != ')') { 764 i++; 765 } 766 end = i; 767 i++; 768 } else if ((mode&PROC_QUOTES) != 0) { 769 while (buffer[i] != '"' && i < endIndex) { 770 i++; 771 } 772 end = i; 773 i++; 774 } 775 while (i < endIndex && buffer[i] != term) { 776 i++; 777 } 778 if (end < 0) { 779 end = i; 780 } 781 782 if (i < endIndex) { 783 i++; 784 if ((mode&PROC_COMBINE) != 0) { 785 while (i < endIndex && buffer[i] == term) { 786 i++; 787 } 788 } 789 } 790 791 //ALOGI("Field %" PRId32 ": %" PRId32 "-%" PRId32 " dest=%" PRId32 " mode=0x%" PRIx32 "\n", i, start, end, di, mode); 792 793 if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) { 794 char c = buffer[end]; 795 buffer[end] = 0; 796 if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) { 797 char* end; 798 floatsData[di] = strtof(buffer+start, &end); 799 } 800 if ((mode&PROC_OUT_LONG) != 0 && di < NL) { 801 char* end; 802 longsData[di] = strtoll(buffer+start, &end, 10); 803 } 804 if ((mode&PROC_OUT_STRING) != 0 && di < NS) { 805 jstring str = env->NewStringUTF(buffer+start); 806 env->SetObjectArrayElement(outStrings, di, str); 807 } 808 buffer[end] = c; 809 di++; 810 } 811 } 812 813 env->ReleaseIntArrayElements(format, formatData, 0); 814 if (longsData != NULL) { 815 env->ReleaseLongArrayElements(outLongs, longsData, 0); 816 } 817 if (floatsData != NULL) { 818 env->ReleaseFloatArrayElements(outFloats, floatsData, 0); 819 } 820 821 return res; 822} 823 824jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz, 825 jbyteArray buffer, jint startIndex, jint endIndex, jintArray format, 826 jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) 827{ 828 jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL); 829 830 jboolean result = android_os_Process_parseProcLineArray(env, clazz, 831 (char*) bufferArray, startIndex, endIndex, format, outStrings, 832 outLongs, outFloats); 833 834 env->ReleaseByteArrayElements(buffer, bufferArray, 0); 835 836 return result; 837} 838 839jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, 840 jstring file, jintArray format, jobjectArray outStrings, 841 jlongArray outLongs, jfloatArray outFloats) 842{ 843 if (file == NULL || format == NULL) { 844 jniThrowNullPointerException(env, NULL); 845 return JNI_FALSE; 846 } 847 848 const char* file8 = env->GetStringUTFChars(file, NULL); 849 if (file8 == NULL) { 850 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 851 return JNI_FALSE; 852 } 853 int fd = open(file8, O_RDONLY); 854 855 if (fd < 0) { 856 if (kDebugProc) { 857 ALOGW("Unable to open process file: %s\n", file8); 858 } 859 env->ReleaseStringUTFChars(file, file8); 860 return JNI_FALSE; 861 } 862 env->ReleaseStringUTFChars(file, file8); 863 864 char buffer[256]; 865 const int len = read(fd, buffer, sizeof(buffer)-1); 866 close(fd); 867 868 if (len < 0) { 869 if (kDebugProc) { 870 ALOGW("Unable to open process file: %s fd=%d\n", file8, fd); 871 } 872 return JNI_FALSE; 873 } 874 buffer[len] = 0; 875 876 return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len, 877 format, outStrings, outLongs, outFloats); 878 879} 880 881void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz, 882 jobject binderObject) 883{ 884 if (binderObject == NULL) { 885 jniThrowNullPointerException(env, NULL); 886 return; 887 } 888 889 sp<IBinder> binder = ibinderForJavaObject(env, binderObject); 890} 891 892void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig) 893{ 894 if (pid > 0) { 895 ALOGI("Sending signal. PID: %" PRId32 " SIG: %" PRId32, pid, sig); 896 kill(pid, sig); 897 } 898} 899 900void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig) 901{ 902 if (pid > 0) { 903 kill(pid, sig); 904 } 905} 906 907static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz) 908{ 909 struct timespec ts; 910 911 int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); 912 913 if (res != 0) { 914 return (jlong) 0; 915 } 916 917 nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; 918 return (jlong) nanoseconds_to_milliseconds(when); 919} 920 921static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid) 922{ 923 char filename[64]; 924 925 snprintf(filename, sizeof(filename), "/proc/%" PRId32 "/smaps", pid); 926 927 FILE * file = fopen(filename, "r"); 928 if (!file) { 929 return (jlong) -1; 930 } 931 932 // Tally up all of the Pss from the various maps 933 char line[256]; 934 jlong pss = 0; 935 while (fgets(line, sizeof(line), file)) { 936 jlong v; 937 if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) { 938 pss += v; 939 } 940 } 941 942 fclose(file); 943 944 // Return the Pss value in bytes, not kilobytes 945 return pss * 1024; 946} 947 948jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz, 949 jobjectArray commandNames) 950{ 951 if (commandNames == NULL) { 952 jniThrowNullPointerException(env, NULL); 953 return NULL; 954 } 955 956 Vector<String8> commands; 957 958 jsize count = env->GetArrayLength(commandNames); 959 960 for (int i=0; i<count; i++) { 961 jobject obj = env->GetObjectArrayElement(commandNames, i); 962 if (obj != NULL) { 963 const char* str8 = env->GetStringUTFChars((jstring)obj, NULL); 964 if (str8 == NULL) { 965 jniThrowNullPointerException(env, "Element in commandNames"); 966 return NULL; 967 } 968 commands.add(String8(str8)); 969 env->ReleaseStringUTFChars((jstring)obj, str8); 970 } else { 971 jniThrowNullPointerException(env, "Element in commandNames"); 972 return NULL; 973 } 974 } 975 976 Vector<jint> pids; 977 978 DIR *proc = opendir("/proc"); 979 if (proc == NULL) { 980 fprintf(stderr, "/proc: %s\n", strerror(errno)); 981 return NULL; 982 } 983 984 struct dirent *d; 985 while ((d = readdir(proc))) { 986 int pid = atoi(d->d_name); 987 if (pid <= 0) continue; 988 989 char path[PATH_MAX]; 990 char data[PATH_MAX]; 991 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 992 993 int fd = open(path, O_RDONLY); 994 if (fd < 0) { 995 continue; 996 } 997 const int len = read(fd, data, sizeof(data)-1); 998 close(fd); 999 1000 if (len < 0) { 1001 continue; 1002 } 1003 data[len] = 0; 1004 1005 for (int i=0; i<len; i++) { 1006 if (data[i] == ' ') { 1007 data[i] = 0; 1008 break; 1009 } 1010 } 1011 1012 for (size_t i=0; i<commands.size(); i++) { 1013 if (commands[i] == data) { 1014 pids.add(pid); 1015 break; 1016 } 1017 } 1018 } 1019 1020 closedir(proc); 1021 1022 jintArray pidArray = env->NewIntArray(pids.size()); 1023 if (pidArray == NULL) { 1024 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 1025 return NULL; 1026 } 1027 1028 if (pids.size() > 0) { 1029 env->SetIntArrayRegion(pidArray, 0, pids.size(), pids.array()); 1030 } 1031 1032 return pidArray; 1033} 1034 1035jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid) 1036{ 1037 return killProcessGroup(uid, pid, SIGKILL); 1038} 1039 1040void android_os_Process_removeAllProcessGroups(JNIEnv* env, jobject clazz) 1041{ 1042 return removeAllProcessGroups(); 1043} 1044 1045static const JNINativeMethod methods[] = { 1046 {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName}, 1047 {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName}, 1048 {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority}, 1049 {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler}, 1050 {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground}, 1051 {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority}, 1052 {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority}, 1053 {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, 1054 {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup}, 1055 {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup}, 1056 {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness}, 1057 {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0}, 1058 {"setUid", "(I)I", (void*)android_os_Process_setUid}, 1059 {"setGid", "(I)I", (void*)android_os_Process_setGid}, 1060 {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal}, 1061 {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet}, 1062 {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory}, 1063 {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory}, 1064 {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines}, 1065 {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids}, 1066 {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile}, 1067 {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine}, 1068 {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime}, 1069 {"getPss", "(I)J", (void*)android_os_Process_getPss}, 1070 {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands}, 1071 //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject}, 1072 {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup}, 1073 {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups}, 1074}; 1075 1076int register_android_os_Process(JNIEnv* env) 1077{ 1078 return RegisterMethodsOrDie(env, "android/os/Process", methods, NELEM(methods)); 1079} 1080