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