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 
printErrno(const char * msg,const char * filename)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.
readStringFromFile(const char * filename,char * const start,size_t size,bool must_exist=true)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 //
writeStringToFile(const char * filename,const char * start,bool must_exist=true)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 
writeIntToFile(const char * filename,long value)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.
reasonChildExited(int status)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 
kernelVersion(char * str,size_t size)235 int kernelVersion(char *str, size_t size)
236 {
237     return readStringFromFile(kKernelVersion, str, size);
238 }
239 
pidOutOfMemoryAdj()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 
setPidOutOfMemoryAdj(int level)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 
disableCpuScaling()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 
schedFeatures(char * str,size_t size)285 int schedFeatures(char *str, size_t size)
286 {
287     return readStringFromFile(kSchedFeatures, str, size);
288 }
289 
newFairSleepers()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 
setNewFairSleepers(bool on)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 
normalizedSleepers()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 
setNormalizedSleepers(bool on)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 
forkOrExit()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 
waitForChildrenOrExit(int num)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.
syncAndDropCaches(int code)390 void syncAndDropCaches(int code)
391 {
392     sync();
393     sync();
394     writeIntToFile(kDropCaches, code);
395     sleep(kCachePurgeSleepDuration);
396 }
397 
398 
fsyncAndDropCaches(int fd,int code)399 void fsyncAndDropCaches(int fd, int code)
400 {
401     fsync(fd);
402     fsync(fd);
403     writeIntToFile(kDropCaches, code);
404     sleep(kCachePurgeSleepDuration);
405 }
406 
407 
resetDirectory(const char * directory)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
writePidAndWaitForReply(int writefd,int readfd)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 
waitForChildrenAndSignal(int mProcessNb,int readfd,int writefd)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