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