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 41 namespace { 42 const int kError = -1; 43 // Max number of retries on EAGAIN and EINTR. Totally arbitrary. 44 const int kMaxAttempts = 8; 45 46 // How long to wait after a cache purge. A few seconds (arbitrary). 47 const int kCachePurgeSleepDuration = 2; // seconds 48 49 const bool kSilentIfMissing = false; 50 51 const char *kKernelVersion = "/proc/version"; 52 const char *kScalingGovernorFormat = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor"; 53 const char *kDropCaches = "/proc/sys/vm/drop_caches"; 54 const char *kSchedFeatures = "/sys/kernel/debug/sched_features"; 55 const char *kNewFairSleepers = "NEW_FAIR_SLEEPERS"; 56 const char *kNoNewFairSleepers = "NO_NEW_FAIR_SLEEPERS"; 57 const char *kNormalizedSleepers = "NORMALIZED_SLEEPER"; // no 's' at the end 58 const char *kNoNormalizedSleepers = "NO_NORMALIZED_SLEEPER"; 59 60 const 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 65 void 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. 77 int 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 // 146 int 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 201 int 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. 211 const 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 233 namespace android { 234 235 int kernelVersion(char *str, size_t size) 236 { 237 return readStringFromFile(kKernelVersion, str, size); 238 } 239 240 int 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 257 void 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 265 void 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 285 int schedFeatures(char *str, size_t size) 286 { 287 return readStringFromFile(kSchedFeatures, str, size); 288 } 289 290 bool 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 302 void 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 320 bool 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 332 void 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 350 pid_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 362 void 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. 390 void syncAndDropCaches(int code) 391 { 392 sync(); 393 sync(); 394 writeIntToFile(kDropCaches, code); 395 sleep(kCachePurgeSleepDuration); 396 } 397 398 399 void fsyncAndDropCaches(int fd, int code) 400 { 401 fsync(fd); 402 fsync(fd); 403 writeIntToFile(kDropCaches, code); 404 sleep(kCachePurgeSleepDuration); 405 } 406 407 408 void 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 438 bool 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 515 bool 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