1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <dirent.h> 30#include <errno.h> 31#include <fcntl.h> 32#include <limits.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <sys/stat.h> 36#include <sys/types.h> 37#include <sys/wait.h> 38#include <unistd.h> 39#include "sysutil.h" 40 41namespace { 42const int kError = -1; 43// Max number of retries on EAGAIN and EINTR. Totally arbitrary. 44const int kMaxAttempts = 8; 45 46// How long to wait after a cache purge. A few seconds (arbitrary). 47const int kCachePurgeSleepDuration = 2; // seconds 48 49const bool kSilentIfMissing = false; 50 51const char *kKernelVersion = "/proc/version"; 52const char *kScalingGovernorFormat = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor"; 53const char *kDropCaches = "/proc/sys/vm/drop_caches"; 54const char *kSchedFeatures = "/sys/kernel/debug/sched_features"; 55const char *kNewFairSleepers = "NEW_FAIR_SLEEPERS"; 56const char *kNoNewFairSleepers = "NO_NEW_FAIR_SLEEPERS"; 57const char *kNormalizedSleepers = "NORMALIZED_SLEEPER"; // no 's' at the end 58const char *kNoNormalizedSleepers = "NO_NORMALIZED_SLEEPER"; 59 60const char *kDebugfsWarningMsg = "Did you 'adb root; adb shell mount -t debugfs none /sys/kernel/debug' ?"; 61 62// TODO: Surely these file utility functions must exist already. A 63// quick grep did not turn up anything. Look harder later. 64 65void printErrno(const char *msg, const char *filename) 66{ 67 fprintf(stderr, "# %s %s %d %s\n", msg, filename, errno, strerror(errno)); 68} 69 70// Read a C-string from a file. If the buffer is too short, an error 71// message will be printed on stderr. 72// @param filename Of the file to read. 73// @param start Buffer where the data should be written to. 74// @param size The size of the buffer pointed by str. Must be >= 1. 75// @return The number of characters read (not including the trailing'\0' used 76// to end the string) or -1 if there was an error. 77int readStringFromFile(const char *filename, char *const start, size_t size, bool must_exist=true) 78{ 79 if (NULL == start || size == 0) 80 { 81 return 0; 82 } 83 char *end = start; 84 int fd = open(filename, O_RDONLY); 85 86 if (fd < 0) 87 { 88 if (ENOENT != errno || must_exist) 89 { 90 printErrno("Failed to open", filename); 91 } 92 return kError; 93 } 94 95 bool eof = false; 96 bool error = false; 97 int attempts = 0; 98 99 --size; // reserve space for trailing '\0' 100 101 while (size > 0 && !error && !eof && attempts < kMaxAttempts) 102 { 103 ssize_t s; 104 105 s = read(fd, end, size); 106 107 if (s < 0) 108 { 109 error = EAGAIN != errno && EINTR != errno; 110 if (error) 111 { 112 printErrno("Failed to read", filename); 113 } 114 } 115 else if (0 == s) 116 { 117 eof = true; 118 } 119 else 120 { 121 end += s; 122 size -= s; 123 } 124 ++attempts; 125 } 126 127 close(fd); 128 129 if (error) 130 { 131 return kError; 132 } 133 else 134 { 135 *end = '\0'; 136 if (!eof) 137 { 138 fprintf(stderr, "Buffer too small for %s\n", filename); 139 } 140 return end - start; 141 } 142} 143 144// Write a C string ('\0' terminated) to a file. 145// 146int writeStringToFile(const char *filename, const char *start, bool must_exist=true) 147{ 148 int fd = open(filename, O_WRONLY); 149 150 151 if (fd < 0) 152 { 153 if (ENOENT != errno || must_exist) 154 { 155 printErrno("Failed to open", filename); 156 } 157 return kError; 158 } 159 160 const size_t len = strlen(start); 161 size_t size = len; 162 bool error = false; 163 int attempts = 0; 164 165 while (size > 0 && !error && attempts < kMaxAttempts) 166 { 167 ssize_t s = write(fd, start, size); 168 169 if (s < 0) 170 { 171 error = EAGAIN != errno && EINTR != errno; 172 if (error) 173 { 174 printErrno("Failed to write", filename); 175 } 176 } 177 else 178 { 179 start += s; 180 size -= s; 181 } 182 ++attempts; 183 } 184 close(fd); 185 186 if (error) 187 { 188 return kError; 189 } 190 else 191 { 192 if (size > 0) 193 { 194 fprintf(stderr, "Partial write to %s (%d out of %d)\n", 195 filename, size, len); 196 } 197 return len - size; 198 } 199} 200 201int writeIntToFile(const char *filename, long value) 202{ 203 char buffer[16] = {0,}; 204 sprintf(buffer, "%ld", value); 205 return writeStringToFile(filename, buffer); 206} 207 208// @return a message describing the reason why the child exited. The 209// message is in a shared buffer, not thread safe, erased by 210// subsequent calls. 211const char *reasonChildExited(int status) 212{ 213 static char buffer[80]; 214 215 if (WIFEXITED(status)) 216 { 217 snprintf(buffer, sizeof(buffer), "ok (%d)", WEXITSTATUS(status)); 218 } 219 else if (WIFSIGNALED(status)) 220 { 221 snprintf(buffer, sizeof(buffer), "signaled (%d %s)", WTERMSIG(status), strsignal(WTERMSIG(status))); 222 } 223 else 224 { 225 snprintf(buffer, sizeof(buffer), "stopped?"); 226 } 227 return buffer; 228} 229 230 231} // anonymous namespace 232 233namespace android { 234 235int kernelVersion(char *str, size_t size) 236{ 237 return readStringFromFile(kKernelVersion, str, size); 238} 239 240int pidOutOfMemoryAdj() 241{ 242 char filename[FILENAME_MAX]; 243 244 snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid()); 245 246 char value[16]; 247 if (readStringFromFile(filename, value, sizeof(value)) == -1) 248 { 249 return -127; 250 } 251 else 252 { 253 return atoi(value); 254 } 255} 256 257void setPidOutOfMemoryAdj(int level) 258{ 259 char filename[FILENAME_MAX]; 260 261 snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid()); 262 writeIntToFile(filename, level); 263} 264 265void disableCpuScaling() 266{ 267 for (int cpu = 0; cpu < 16; ++cpu) // 16 cores mobile phones, abestos pockets recommended. 268 { 269 char governor[FILENAME_MAX]; 270 sprintf(governor, kScalingGovernorFormat, cpu); 271 272 if (writeStringToFile(governor, "performance", kSilentIfMissing) < 0) 273 { 274 if (cpu > 0 && errno == ENOENT) 275 { 276 break; // cpu1 or above not found, ok since we have cpu0. 277 } 278 fprintf(stderr, "Failed to write to scaling governor file for cpu %d: %d %s", 279 cpu, errno, strerror(errno)); 280 break; 281 } 282 } 283} 284 285int schedFeatures(char *str, size_t size) 286{ 287 return readStringFromFile(kSchedFeatures, str, size); 288} 289 290bool newFairSleepers() 291{ 292 char value[256] = {0,}; 293 294 if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1) 295 { 296 printErrno(kDebugfsWarningMsg, kSchedFeatures); 297 return false; 298 } 299 return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL; 300} 301 302void setNewFairSleepers(bool on) 303{ 304 int retcode; 305 306 if (on) 307 { 308 retcode = writeStringToFile(kSchedFeatures, kNewFairSleepers); 309 } 310 else 311 { 312 retcode = writeStringToFile(kSchedFeatures, kNoNewFairSleepers); 313 } 314 if (retcode < 0) 315 { 316 fprintf(stderr, "# %s\n", kDebugfsWarningMsg); 317 } 318} 319 320bool normalizedSleepers() 321{ 322 char value[256] = {0,}; 323 324 if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1) 325 { 326 printErrno(kDebugfsWarningMsg, kSchedFeatures); 327 return false; 328 } 329 return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL; 330} 331 332void setNormalizedSleepers(bool on) 333{ 334 int retcode; 335 336 if (on) 337 { 338 retcode = writeStringToFile(kSchedFeatures, kNormalizedSleepers); 339 } 340 else 341 { 342 retcode = writeStringToFile(kSchedFeatures, kNoNormalizedSleepers); 343 } 344 if (retcode < 0) 345 { 346 fprintf(stderr, "# %s\n", kDebugfsWarningMsg); 347 } 348} 349 350pid_t forkOrExit() 351{ 352 pid_t childpid = fork(); 353 354 if (-1 == childpid) 355 { 356 fprintf(stderr, "Fork failed: %d %s", errno, strerror(errno)); 357 exit(EXIT_FAILURE); 358 } 359 return childpid; 360} 361 362void waitForChildrenOrExit(int num) 363{ 364 while (num > 0) 365 { 366 int status; 367 pid_t pid = wait(&status); 368 if (-1 == pid) 369 { 370 fprintf(stderr, "Wait failed\n"); 371 } 372 else 373 { 374 if (!WIFEXITED(status)) 375 { 376 fprintf(stderr, "Child pid %d did not exit cleanly %s\n", 377 pid, reasonChildExited(status)); 378 exit(EXIT_FAILURE); 379 } 380 } 381 --num; 382 } 383} 384 385// Sync and cache cleaning functions. In the old hpux days I was told 386// to always call *sync twice. The same advice seems to be still true 387// today so *sync is called twice. 388// Also we wait 'a little' to give a chance to background threads to 389// purge their caches. 390void syncAndDropCaches(int code) 391{ 392 sync(); 393 sync(); 394 writeIntToFile(kDropCaches, code); 395 sleep(kCachePurgeSleepDuration); 396} 397 398 399void fsyncAndDropCaches(int fd, int code) 400{ 401 fsync(fd); 402 fsync(fd); 403 writeIntToFile(kDropCaches, code); 404 sleep(kCachePurgeSleepDuration); 405} 406 407 408void resetDirectory(const char *directory) 409{ 410 DIR *dir = opendir(directory); 411 412 if (NULL != dir) 413 { 414 struct dirent *entry; 415 char name_buffer[PATH_MAX]; 416 417 while((entry = readdir(dir))) 418 { 419 if (0 == strcmp(entry->d_name, ".") 420 || 0 == strcmp(entry->d_name, "..") 421 || 0 == strcmp(entry->d_name, "lost+found")) 422 { 423 continue; 424 } 425 strcpy(name_buffer, directory); 426 strcat(name_buffer, "/"); 427 strcat(name_buffer, entry->d_name); 428 unlink(name_buffer); 429 } 430 closedir(dir); 431 } else { 432 mkdir(directory, S_IRWXU); 433 } 434} 435 436 437// IPC 438bool writePidAndWaitForReply(int writefd, int readfd) 439{ 440 if (writefd > readfd) 441 { 442 fprintf(stderr, "Called with args in wrong order!!\n"); 443 return false; 444 } 445 pid_t pid = getpid(); 446 char *start = reinterpret_cast<char *>(&pid); 447 size_t size = sizeof(pid); 448 bool error = false; 449 int attempts = 0; 450 451 while (size > 0 && !error && attempts < kMaxAttempts) 452 { 453 ssize_t s = write(writefd, start, size); 454 455 if (s < 0) 456 { 457 error = EAGAIN != errno && EINTR != errno; 458 if (error) 459 { 460 printErrno("Failed to write", "parent"); 461 } 462 } 463 else 464 { 465 start += s; 466 size -= s; 467 } 468 ++attempts; 469 } 470 471 if (error || 0 != size) 472 { 473 return false; 474 } 475 476 bool eof = false; 477 char dummy; 478 size = sizeof(dummy); 479 error = false; 480 attempts = 0; 481 482 while (size > 0 && !error && !eof && attempts < kMaxAttempts) 483 { 484 ssize_t s; 485 486 s = read(readfd, &dummy, size); 487 488 if (s < 0) 489 { 490 error = EAGAIN != errno && EINTR != errno; 491 if (error) 492 { 493 printErrno("Failed to read", "parent"); 494 } 495 } 496 else if (0 == s) 497 { 498 eof = true; 499 } 500 else 501 { 502 size -= s; 503 } 504 ++attempts; 505 } 506 if (error || 0 != size) 507 { 508 return false; 509 } 510 return true; 511} 512 513 514 515bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd) 516{ 517 if (readfd > writefd) 518 { 519 fprintf(stderr, "Called with args in wrong order!!\n"); 520 return false; 521 } 522 523 bool error; 524 int attempts; 525 size_t size; 526 527 for (int p = 0; p < mProcessNb; ++p) 528 { 529 bool eof = false; 530 pid_t pid; 531 char *end = reinterpret_cast<char *>(&pid); 532 533 error = false; 534 attempts = 0; 535 size = sizeof(pid); 536 537 while (size > 0 && !error && !eof && attempts < kMaxAttempts) 538 { 539 ssize_t s; 540 541 s = read(readfd, end, size); 542 543 if (s < 0) 544 { 545 error = EAGAIN != errno && EINTR != errno; 546 if (error) 547 { 548 printErrno("Failed to read", "child"); 549 } 550 } 551 else if (0 == s) 552 { 553 eof = true; 554 } 555 else 556 { 557 end += s; 558 size -= s; 559 } 560 ++attempts; 561 } 562 563 if (error || 0 != size) 564 { 565 return false; 566 } 567 } 568 569 for (int p = 0; p < mProcessNb; ++p) 570 { 571 char dummy; 572 573 error = false; 574 attempts = 0; 575 size = sizeof(dummy); 576 577 while (size > 0 && !error && attempts < kMaxAttempts) 578 { 579 ssize_t s = write(writefd, &dummy, size); 580 581 if (s < 0) 582 { 583 error = EAGAIN != errno && EINTR != errno; 584 if (error) 585 { 586 printErrno("Failed to write", "child"); 587 } 588 } 589 else 590 { 591 size -= s; 592 } 593 ++attempts; 594 } 595 596 if (error || 0 != size) 597 { 598 return false; 599 } 600 } 601 return true; 602} 603 604} // namespace android 605