android_util_Process.cpp revision ed6b9dff563c5e22f040ff37e12c0d771e0478ae
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 it's current audio group so it can keep it's budget 243 continue; 244 } 245 } 246 247 if (isDefault) { 248 if (t_pri >= ANDROID_PRIORITY_BACKGROUND) { 249 // This task wants to stay at background 250 continue; 251 } 252 } 253 254 int err = set_sched_policy(t_pid, sp); 255 if (err != NO_ERROR) { 256 signalExceptionForGroupError(env, -err); 257 break; 258 } 259 } 260 closedir(d); 261} 262 263jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid) 264{ 265 SchedPolicy sp; 266 if (get_sched_policy(pid, &sp) != 0) { 267 signalExceptionForGroupError(env, errno); 268 } 269 return (int) sp; 270} 271 272static 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 ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid()); 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 289void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz, 290 jint tid, jint policy, jint pri) 291{ 292// linux has sched_setscheduler(), others don't. 293#if defined(__linux__) 294 struct sched_param param; 295 param.sched_priority = pri; 296 int rc = sched_setscheduler(tid, policy, ¶m); 297 if (rc) { 298 signalExceptionForPriorityError(env, errno); 299 } 300#else 301 signalExceptionForPriorityError(env, ENOSYS); 302#endif 303} 304 305void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, 306 jint pid, jint pri) 307{ 308#if GUARD_THREAD_PRIORITY 309 // if we're putting the current thread into the background, check the TLS 310 // to make sure this thread isn't guarded. If it is, raise an exception. 311 if (pri >= ANDROID_PRIORITY_BACKGROUND) { 312 if (pid == gettid()) { 313 void* bgOk = pthread_getspecific(gBgKey); 314 if (bgOk == ((void*)0xbaad)) { 315 ALOGE("Thread marked fg-only put self in background!"); 316 jniThrowException(env, "java/lang/SecurityException", "May not put this thread into background"); 317 return; 318 } 319 } 320 } 321#endif 322 323 int rc = androidSetThreadPriority(pid, pri); 324 if (rc != 0) { 325 if (rc == INVALID_OPERATION) { 326 signalExceptionForPriorityError(env, errno); 327 } else { 328 signalExceptionForGroupError(env, errno); 329 } 330 } 331 332 //ALOGI("Setting priority of %" PRId32 ": %" PRId32 ", getpriority returns %d\n", 333 // pid, pri, getpriority(PRIO_PROCESS, pid)); 334} 335 336void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz, 337 jint pri) 338{ 339 android_os_Process_setThreadPriority(env, clazz, gettid(), pri); 340} 341 342jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz, 343 jint pid) 344{ 345 errno = 0; 346 jint pri = getpriority(PRIO_PROCESS, pid); 347 if (errno != 0) { 348 signalExceptionForPriorityError(env, errno); 349 } 350 //ALOGI("Returning priority of %" PRId32 ": %" PRId32 "\n", pid, pri); 351 return pri; 352} 353 354jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz, 355 jint pid, jboolean is_increased) 356{ 357 char text[64]; 358 359 if (is_increased) { 360 strcpy(text, "/sys/fs/cgroup/memory/sw/tasks"); 361 } else { 362 strcpy(text, "/sys/fs/cgroup/memory/tasks"); 363 } 364 365 struct stat st; 366 if (stat(text, &st) || !S_ISREG(st.st_mode)) { 367 return false; 368 } 369 370 int fd = open(text, O_WRONLY); 371 if (fd >= 0) { 372 sprintf(text, "%" PRId32, pid); 373 write(fd, text, strlen(text)); 374 close(fd); 375 } 376 377 return true; 378} 379 380void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name) 381{ 382 if (name == NULL) { 383 jniThrowNullPointerException(env, NULL); 384 return; 385 } 386 387 const jchar* str = env->GetStringCritical(name, 0); 388 String8 name8; 389 if (str) { 390 name8 = String8(reinterpret_cast<const char16_t*>(str), 391 env->GetStringLength(name)); 392 env->ReleaseStringCritical(name, str); 393 } 394 395 if (name8.size() > 0) { 396 const char* procName = name8.string(); 397 set_process_name(procName); 398 AndroidRuntime::getRuntime()->setArgv0(procName); 399 } 400} 401 402jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid) 403{ 404 return setuid(uid) == 0 ? 0 : errno; 405} 406 407jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid) 408{ 409 return setgid(uid) == 0 ? 0 : errno; 410} 411 412static int pid_compare(const void* v1, const void* v2) 413{ 414 //ALOGI("Compare %" PRId32 " vs %" PRId32 "\n", *((const jint*)v1), *((const jint*)v2)); 415 return *((const jint*)v1) - *((const jint*)v2); 416} 417 418static jlong getFreeMemoryImpl(const char* const sums[], const size_t sumsLen[], size_t num) 419{ 420 int fd = open("/proc/meminfo", O_RDONLY); 421 422 if (fd < 0) { 423 ALOGW("Unable to open /proc/meminfo"); 424 return -1; 425 } 426 427 char buffer[256]; 428 const int len = read(fd, buffer, sizeof(buffer)-1); 429 close(fd); 430 431 if (len < 0) { 432 ALOGW("Unable to read /proc/meminfo"); 433 return -1; 434 } 435 buffer[len] = 0; 436 437 size_t numFound = 0; 438 jlong mem = 0; 439 440 char* p = buffer; 441 while (*p && numFound < num) { 442 int i = 0; 443 while (sums[i]) { 444 if (strncmp(p, sums[i], sumsLen[i]) == 0) { 445 p += sumsLen[i]; 446 while (*p == ' ') p++; 447 char* num = p; 448 while (*p >= '0' && *p <= '9') p++; 449 if (*p != 0) { 450 *p = 0; 451 p++; 452 if (*p == 0) p--; 453 } 454 mem += atoll(num) * 1024; 455 numFound++; 456 break; 457 } 458 i++; 459 } 460 p++; 461 } 462 463 return numFound > 0 ? mem : -1; 464} 465 466static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz) 467{ 468 static const char* const sums[] = { "MemFree:", "Cached:", NULL }; 469 static const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 }; 470 return getFreeMemoryImpl(sums, sumsLen, 2); 471} 472 473static jlong android_os_Process_getTotalMemory(JNIEnv* env, jobject clazz) 474{ 475 static const char* const sums[] = { "MemTotal:", NULL }; 476 static const size_t sumsLen[] = { strlen("MemTotal:"), 0 }; 477 return getFreeMemoryImpl(sums, sumsLen, 1); 478} 479 480void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr, 481 jobjectArray reqFields, jlongArray outFields) 482{ 483 //ALOGI("getMemInfo: %p %p", reqFields, outFields); 484 485 if (fileStr == NULL || reqFields == NULL || outFields == NULL) { 486 jniThrowNullPointerException(env, NULL); 487 return; 488 } 489 490 const char* file8 = env->GetStringUTFChars(fileStr, NULL); 491 if (file8 == NULL) { 492 return; 493 } 494 String8 file(file8); 495 env->ReleaseStringUTFChars(fileStr, file8); 496 497 jsize count = env->GetArrayLength(reqFields); 498 if (count > env->GetArrayLength(outFields)) { 499 jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ"); 500 return; 501 } 502 503 Vector<String8> fields; 504 int i; 505 506 for (i=0; i<count; i++) { 507 jobject obj = env->GetObjectArrayElement(reqFields, i); 508 if (obj != NULL) { 509 const char* str8 = env->GetStringUTFChars((jstring)obj, NULL); 510 //ALOGI("String at %d: %p = %s", i, obj, str8); 511 if (str8 == NULL) { 512 jniThrowNullPointerException(env, "Element in reqFields"); 513 return; 514 } 515 fields.add(String8(str8)); 516 env->ReleaseStringUTFChars((jstring)obj, str8); 517 } else { 518 jniThrowNullPointerException(env, "Element in reqFields"); 519 return; 520 } 521 } 522 523 jlong* sizesArray = env->GetLongArrayElements(outFields, 0); 524 if (sizesArray == NULL) { 525 return; 526 } 527 528 //ALOGI("Clearing %" PRId32 " sizes", count); 529 for (i=0; i<count; i++) { 530 sizesArray[i] = 0; 531 } 532 533 int fd = open(file.string(), O_RDONLY); 534 535 if (fd >= 0) { 536 const size_t BUFFER_SIZE = 2048; 537 char* buffer = (char*)malloc(BUFFER_SIZE); 538 int len = read(fd, buffer, BUFFER_SIZE-1); 539 close(fd); 540 541 if (len < 0) { 542 ALOGW("Unable to read %s", file.string()); 543 len = 0; 544 } 545 buffer[len] = 0; 546 547 int foundCount = 0; 548 549 char* p = buffer; 550 while (*p && foundCount < count) { 551 bool skipToEol = true; 552 //ALOGI("Parsing at: %s", p); 553 for (i=0; i<count; i++) { 554 const String8& field = fields[i]; 555 if (strncmp(p, field.string(), field.length()) == 0) { 556 p += field.length(); 557 while (*p == ' ' || *p == '\t') p++; 558 char* num = p; 559 while (*p >= '0' && *p <= '9') p++; 560 skipToEol = *p != '\n'; 561 if (*p != 0) { 562 *p = 0; 563 p++; 564 } 565 char* end; 566 sizesArray[i] = strtoll(num, &end, 10); 567 //ALOGI("Field %s = %" PRId64, field.string(), sizesArray[i]); 568 foundCount++; 569 break; 570 } 571 } 572 if (skipToEol) { 573 while (*p && *p != '\n') { 574 p++; 575 } 576 if (*p == '\n') { 577 p++; 578 } 579 } 580 } 581 582 free(buffer); 583 } else { 584 ALOGW("Unable to open %s", file.string()); 585 } 586 587 //ALOGI("Done!"); 588 env->ReleaseLongArrayElements(outFields, sizesArray, 0); 589} 590 591jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz, 592 jstring file, jintArray lastArray) 593{ 594 if (file == NULL) { 595 jniThrowNullPointerException(env, NULL); 596 return NULL; 597 } 598 599 const char* file8 = env->GetStringUTFChars(file, NULL); 600 if (file8 == NULL) { 601 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 602 return NULL; 603 } 604 605 DIR* dirp = opendir(file8); 606 607 env->ReleaseStringUTFChars(file, file8); 608 609 if(dirp == NULL) { 610 return NULL; 611 } 612 613 jsize curCount = 0; 614 jint* curData = NULL; 615 if (lastArray != NULL) { 616 curCount = env->GetArrayLength(lastArray); 617 curData = env->GetIntArrayElements(lastArray, 0); 618 } 619 620 jint curPos = 0; 621 622 struct dirent* entry; 623 while ((entry=readdir(dirp)) != NULL) { 624 const char* p = entry->d_name; 625 while (*p) { 626 if (*p < '0' || *p > '9') break; 627 p++; 628 } 629 if (*p != 0) continue; 630 631 char* end; 632 int pid = strtol(entry->d_name, &end, 10); 633 //ALOGI("File %s pid=%d\n", entry->d_name, pid); 634 if (curPos >= curCount) { 635 jsize newCount = (curCount == 0) ? 10 : (curCount*2); 636 jintArray newArray = env->NewIntArray(newCount); 637 if (newArray == NULL) { 638 closedir(dirp); 639 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 640 return NULL; 641 } 642 jint* newData = env->GetIntArrayElements(newArray, 0); 643 if (curData != NULL) { 644 memcpy(newData, curData, sizeof(jint)*curCount); 645 env->ReleaseIntArrayElements(lastArray, curData, 0); 646 } 647 lastArray = newArray; 648 curCount = newCount; 649 curData = newData; 650 } 651 652 curData[curPos] = pid; 653 curPos++; 654 } 655 656 closedir(dirp); 657 658 if (curData != NULL && curPos > 0) { 659 qsort(curData, curPos, sizeof(jint), pid_compare); 660 } 661 662 while (curPos < curCount) { 663 curData[curPos] = -1; 664 curPos++; 665 } 666 667 if (curData != NULL) { 668 env->ReleaseIntArrayElements(lastArray, curData, 0); 669 } 670 671 return lastArray; 672} 673 674enum { 675 PROC_TERM_MASK = 0xff, 676 PROC_ZERO_TERM = 0, 677 PROC_SPACE_TERM = ' ', 678 PROC_COMBINE = 0x100, 679 PROC_PARENS = 0x200, 680 PROC_QUOTES = 0x400, 681 PROC_OUT_STRING = 0x1000, 682 PROC_OUT_LONG = 0x2000, 683 PROC_OUT_FLOAT = 0x4000, 684}; 685 686jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, 687 char* buffer, jint startIndex, jint endIndex, jintArray format, 688 jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) 689{ 690 691 const jsize NF = env->GetArrayLength(format); 692 const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0; 693 const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0; 694 const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0; 695 696 jint* formatData = env->GetIntArrayElements(format, 0); 697 jlong* longsData = outLongs ? 698 env->GetLongArrayElements(outLongs, 0) : NULL; 699 jfloat* floatsData = outFloats ? 700 env->GetFloatArrayElements(outFloats, 0) : NULL; 701 if (formatData == NULL || (NL > 0 && longsData == NULL) 702 || (NR > 0 && floatsData == NULL)) { 703 if (formatData != NULL) { 704 env->ReleaseIntArrayElements(format, formatData, 0); 705 } 706 if (longsData != NULL) { 707 env->ReleaseLongArrayElements(outLongs, longsData, 0); 708 } 709 if (floatsData != NULL) { 710 env->ReleaseFloatArrayElements(outFloats, floatsData, 0); 711 } 712 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 713 return JNI_FALSE; 714 } 715 716 jsize i = startIndex; 717 jsize di = 0; 718 719 jboolean res = JNI_TRUE; 720 721 for (jsize fi=0; fi<NF; fi++) { 722 jint mode = formatData[fi]; 723 if ((mode&PROC_PARENS) != 0) { 724 i++; 725 } else if ((mode&PROC_QUOTES) != 0) { 726 if (buffer[i] == '"') { 727 i++; 728 } else { 729 mode &= ~PROC_QUOTES; 730 } 731 } 732 const char term = (char)(mode&PROC_TERM_MASK); 733 const jsize start = i; 734 if (i >= endIndex) { 735 if (kDebugProc) { 736 ALOGW("Ran off end of data @%d", i); 737 } 738 res = JNI_FALSE; 739 break; 740 } 741 742 jsize end = -1; 743 if ((mode&PROC_PARENS) != 0) { 744 while (i < endIndex && buffer[i] != ')') { 745 i++; 746 } 747 end = i; 748 i++; 749 } else if ((mode&PROC_QUOTES) != 0) { 750 while (buffer[i] != '"' && i < endIndex) { 751 i++; 752 } 753 end = i; 754 i++; 755 } 756 while (i < endIndex && buffer[i] != term) { 757 i++; 758 } 759 if (end < 0) { 760 end = i; 761 } 762 763 if (i < endIndex) { 764 i++; 765 if ((mode&PROC_COMBINE) != 0) { 766 while (i < endIndex && buffer[i] == term) { 767 i++; 768 } 769 } 770 } 771 772 //ALOGI("Field %" PRId32 ": %" PRId32 "-%" PRId32 " dest=%" PRId32 " mode=0x%" PRIx32 "\n", i, start, end, di, mode); 773 774 if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) { 775 char c = buffer[end]; 776 buffer[end] = 0; 777 if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) { 778 char* end; 779 floatsData[di] = strtof(buffer+start, &end); 780 } 781 if ((mode&PROC_OUT_LONG) != 0 && di < NL) { 782 char* end; 783 longsData[di] = strtoll(buffer+start, &end, 10); 784 } 785 if ((mode&PROC_OUT_STRING) != 0 && di < NS) { 786 jstring str = env->NewStringUTF(buffer+start); 787 env->SetObjectArrayElement(outStrings, di, str); 788 } 789 buffer[end] = c; 790 di++; 791 } 792 } 793 794 env->ReleaseIntArrayElements(format, formatData, 0); 795 if (longsData != NULL) { 796 env->ReleaseLongArrayElements(outLongs, longsData, 0); 797 } 798 if (floatsData != NULL) { 799 env->ReleaseFloatArrayElements(outFloats, floatsData, 0); 800 } 801 802 return res; 803} 804 805jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz, 806 jbyteArray buffer, jint startIndex, jint endIndex, jintArray format, 807 jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) 808{ 809 jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL); 810 811 jboolean result = android_os_Process_parseProcLineArray(env, clazz, 812 (char*) bufferArray, startIndex, endIndex, format, outStrings, 813 outLongs, outFloats); 814 815 env->ReleaseByteArrayElements(buffer, bufferArray, 0); 816 817 return result; 818} 819 820jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, 821 jstring file, jintArray format, jobjectArray outStrings, 822 jlongArray outLongs, jfloatArray outFloats) 823{ 824 if (file == NULL || format == NULL) { 825 jniThrowNullPointerException(env, NULL); 826 return JNI_FALSE; 827 } 828 829 const char* file8 = env->GetStringUTFChars(file, NULL); 830 if (file8 == NULL) { 831 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 832 return JNI_FALSE; 833 } 834 int fd = open(file8, O_RDONLY); 835 836 if (fd < 0) { 837 if (kDebugProc) { 838 ALOGW("Unable to open process file: %s\n", file8); 839 } 840 env->ReleaseStringUTFChars(file, file8); 841 return JNI_FALSE; 842 } 843 env->ReleaseStringUTFChars(file, file8); 844 845 char buffer[256]; 846 const int len = read(fd, buffer, sizeof(buffer)-1); 847 close(fd); 848 849 if (len < 0) { 850 if (kDebugProc) { 851 ALOGW("Unable to open process file: %s fd=%d\n", file8, fd); 852 } 853 return JNI_FALSE; 854 } 855 buffer[len] = 0; 856 857 return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len, 858 format, outStrings, outLongs, outFloats); 859 860} 861 862void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz, 863 jobject binderObject) 864{ 865 if (binderObject == NULL) { 866 jniThrowNullPointerException(env, NULL); 867 return; 868 } 869 870 sp<IBinder> binder = ibinderForJavaObject(env, binderObject); 871} 872 873void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig) 874{ 875 if (pid > 0) { 876 ALOGI("Sending signal. PID: %" PRId32 " SIG: %" PRId32, pid, sig); 877 kill(pid, sig); 878 } 879} 880 881void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig) 882{ 883 if (pid > 0) { 884 kill(pid, sig); 885 } 886} 887 888static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz) 889{ 890 struct timespec ts; 891 892 int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); 893 894 if (res != 0) { 895 return (jlong) 0; 896 } 897 898 nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; 899 return (jlong) nanoseconds_to_milliseconds(when); 900} 901 902static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid) 903{ 904 char filename[64]; 905 906 snprintf(filename, sizeof(filename), "/proc/%" PRId32 "/smaps", pid); 907 908 FILE * file = fopen(filename, "r"); 909 if (!file) { 910 return (jlong) -1; 911 } 912 913 // Tally up all of the Pss from the various maps 914 char line[256]; 915 jlong pss = 0; 916 while (fgets(line, sizeof(line), file)) { 917 jlong v; 918 if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) { 919 pss += v; 920 } 921 } 922 923 fclose(file); 924 925 // Return the Pss value in bytes, not kilobytes 926 return pss * 1024; 927} 928 929jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz, 930 jobjectArray commandNames) 931{ 932 if (commandNames == NULL) { 933 jniThrowNullPointerException(env, NULL); 934 return NULL; 935 } 936 937 Vector<String8> commands; 938 939 jsize count = env->GetArrayLength(commandNames); 940 941 for (int i=0; i<count; i++) { 942 jobject obj = env->GetObjectArrayElement(commandNames, i); 943 if (obj != NULL) { 944 const char* str8 = env->GetStringUTFChars((jstring)obj, NULL); 945 if (str8 == NULL) { 946 jniThrowNullPointerException(env, "Element in commandNames"); 947 return NULL; 948 } 949 commands.add(String8(str8)); 950 env->ReleaseStringUTFChars((jstring)obj, str8); 951 } else { 952 jniThrowNullPointerException(env, "Element in commandNames"); 953 return NULL; 954 } 955 } 956 957 Vector<jint> pids; 958 959 DIR *proc = opendir("/proc"); 960 if (proc == NULL) { 961 fprintf(stderr, "/proc: %s\n", strerror(errno)); 962 return NULL; 963 } 964 965 struct dirent *d; 966 while ((d = readdir(proc))) { 967 int pid = atoi(d->d_name); 968 if (pid <= 0) continue; 969 970 char path[PATH_MAX]; 971 char data[PATH_MAX]; 972 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 973 974 int fd = open(path, O_RDONLY); 975 if (fd < 0) { 976 continue; 977 } 978 const int len = read(fd, data, sizeof(data)-1); 979 close(fd); 980 981 if (len < 0) { 982 continue; 983 } 984 data[len] = 0; 985 986 for (int i=0; i<len; i++) { 987 if (data[i] == ' ') { 988 data[i] = 0; 989 break; 990 } 991 } 992 993 for (size_t i=0; i<commands.size(); i++) { 994 if (commands[i] == data) { 995 pids.add(pid); 996 break; 997 } 998 } 999 } 1000 1001 closedir(proc); 1002 1003 jintArray pidArray = env->NewIntArray(pids.size()); 1004 if (pidArray == NULL) { 1005 jniThrowException(env, "java/lang/OutOfMemoryError", NULL); 1006 return NULL; 1007 } 1008 1009 if (pids.size() > 0) { 1010 env->SetIntArrayRegion(pidArray, 0, pids.size(), pids.array()); 1011 } 1012 1013 return pidArray; 1014} 1015 1016jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid) 1017{ 1018 return killProcessGroup(uid, pid, SIGKILL); 1019} 1020 1021void android_os_Process_removeAllProcessGroups(JNIEnv* env, jobject clazz) 1022{ 1023 return removeAllProcessGroups(); 1024} 1025 1026static const JNINativeMethod methods[] = { 1027 {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName}, 1028 {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName}, 1029 {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority}, 1030 {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler}, 1031 {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground}, 1032 {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority}, 1033 {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority}, 1034 {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, 1035 {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup}, 1036 {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup}, 1037 {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness}, 1038 {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0}, 1039 {"setUid", "(I)I", (void*)android_os_Process_setUid}, 1040 {"setGid", "(I)I", (void*)android_os_Process_setGid}, 1041 {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal}, 1042 {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet}, 1043 {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory}, 1044 {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory}, 1045 {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines}, 1046 {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids}, 1047 {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile}, 1048 {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine}, 1049 {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime}, 1050 {"getPss", "(I)J", (void*)android_os_Process_getPss}, 1051 {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands}, 1052 //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject}, 1053 {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup}, 1054 {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups}, 1055}; 1056 1057int register_android_os_Process(JNIEnv* env) 1058{ 1059 return RegisterMethodsOrDie(env, "android/os/Process", methods, NELEM(methods)); 1060} 1061