1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/base/file_utils.h"
18 #include "perfetto/ext/base/utils.h"
19 
20 #include "perfetto/base/build_config.h"
21 #include "perfetto/base/logging.h"
22 
23 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
24     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
25     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
26 #include <unistd.h>  // For getpagesize() and geteuid() & fork()
27 #endif
28 
29 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
30 #include <mach/vm_page_size.h>
31 #endif
32 
33 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
34 #include <dlfcn.h>
35 #include <malloc.h>
36 
37 #ifdef M_PURGE
38 #define PERFETTO_M_PURGE M_PURGE
39 #else
40 // Only available in in-tree builds and on newer SDKs.
41 #define PERFETTO_M_PURGE -101
42 #endif
43 
44 namespace {
45 extern "C" {
46 using MalloptType = void (*)(int, int);
47 }
48 }  // namespace
49 #endif  // OS_ANDROID
50 
51 namespace perfetto {
52 namespace base {
53 
MaybeReleaseAllocatorMemToOS()54 void MaybeReleaseAllocatorMemToOS() {
55 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
56   // mallopt() on Android requires SDK level 26. Many targets and embedders
57   // still depend on a lower SDK level. Given mallopt() is a quite simple API,
58   // use reflection to do this rather than bumping the SDK level for all
59   // embedders. This keeps the behavior of standalone builds aligned with
60   // in-tree builds.
61   static MalloptType mallopt_fn =
62       reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
63   if (!mallopt_fn)
64     return;
65   mallopt_fn(PERFETTO_M_PURGE, 0);
66 #endif
67 }
68 
GetSysPageSize()69 uint32_t GetSysPageSize() {
70   ignore_result(kPageSize);  // Just to keep the amalgamated build happy.
71 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
72     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
73   static std::atomic<uint32_t> page_size{0};
74   // This function might be called in hot paths. Avoid calling getpagesize() all
75   // the times, in many implementations getpagesize() calls sysconf() which is
76   // not cheap.
77   uint32_t cached_value = page_size.load(std::memory_order_relaxed);
78   if (PERFETTO_UNLIKELY(cached_value == 0)) {
79     cached_value = static_cast<uint32_t>(getpagesize());
80     page_size.store(cached_value, std::memory_order_relaxed);
81   }
82   return cached_value;
83 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
84   return static_cast<uint32_t>(vm_page_size);
85 #else
86   return 4096;
87 #endif
88 }
89 
GetCurrentUserId()90 uid_t GetCurrentUserId() {
91 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
92     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
93     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
94   return geteuid();
95 #else
96   // TODO(primiano): On Windows we could hash the current user SID and derive a
97   // numeric user id [1]. It is not clear whether we need that. Right now that
98   // would not bring any benefit. Returning 0 unil we can prove we need it.
99   // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
100   return 0;
101 #endif
102 }
103 
SetEnv(const std::string & key,const std::string & value)104 void SetEnv(const std::string& key, const std::string& value) {
105 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
106   PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
107 #else
108   PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
109 #endif
110 }
111 
Daemonize()112 void Daemonize() {
113    #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
114        PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
115        PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
116       pid_t pid;
117       switch (pid = fork()) {
118         case -1:
119           PERFETTO_FATAL("fork");
120         case 0: {
121           PERFETTO_CHECK(setsid() != -1);
122           base::ignore_result(chdir("/"));
123           base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
124           PERFETTO_CHECK(null);
125           PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
126           PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
127           PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
128           // Do not accidentally close stdin/stdout/stderr.
129           if (*null <= 2)
130             null.release();
131           break;
132         }
133         default:
134           printf("%d\n", pid);
135           exit(0);
136       }
137   #else
138     // Avoid -Wunreachable warnings.
139     if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
140       PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
141   #endif  // OS_WIN
142 }
143 
144 }  // namespace base
145 }  // namespace perfetto
146