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