xref: /aosp_15_r20/external/perfetto/src/profiling/common/producer_support.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 "src/profiling/common/producer_support.h"
18 
19 #include <optional>
20 
21 #include "perfetto/ext/base/android_utils.h"
22 #include "perfetto/ext/base/file_utils.h"
23 #include "perfetto/ext/base/string_splitter.h"
24 #include "perfetto/tracing/core/data_source_config.h"
25 #include "src/traced/probes/packages_list/packages_list_parser.h"
26 
27 namespace perfetto {
28 namespace profiling {
29 
30 namespace {
FindInPackagesList(uint64_t lookup_uid,const std::string & packages_list_path)31 std::optional<Package> FindInPackagesList(
32     uint64_t lookup_uid,
33     const std::string& packages_list_path) {
34   std::string content;
35   if (!base::ReadFile(packages_list_path, &content)) {
36     PERFETTO_ELOG("Failed to read %s", packages_list_path.c_str());
37     return std::nullopt;
38   }
39   for (base::StringSplitter ss(std::move(content), '\n'); ss.Next();) {
40     Package pkg;
41     if (!ReadPackagesListLine(ss.cur_token(), &pkg)) {
42       PERFETTO_ELOG("Failed to parse packages.list");
43       return std::nullopt;
44     }
45 
46     if (pkg.uid == lookup_uid) {
47       return std::move(pkg);  // -Wreturn-std-move-in-c++11
48     }
49   }
50   return std::nullopt;
51 }
52 
AllPackagesProfileableByTrustedInitiator(const std::string & packages_list_path)53 bool AllPackagesProfileableByTrustedInitiator(
54     const std::string& packages_list_path) {
55   std::string content;
56   if (!base::ReadFile(packages_list_path, &content)) {
57     PERFETTO_ELOG("Failed to read %s", packages_list_path.c_str());
58     return false;
59   }
60   bool ret = true;
61   for (base::StringSplitter ss(std::move(content), '\n'); ss.Next();) {
62     Package pkg;
63     if (!ReadPackagesListLine(ss.cur_token(), &pkg)) {
64       PERFETTO_ELOG("Failed to parse packages.list");
65       return false;
66     }
67 
68     ret = ret && (pkg.profileable || pkg.debuggable);
69   }
70   return ret;
71 }
72 
73 }  // namespace
74 
CanProfile(const DataSourceConfig & ds_config,uint64_t uid,const std::vector<std::string> & installed_by)75 bool CanProfile(const DataSourceConfig& ds_config,
76                 uint64_t uid,
77                 const std::vector<std::string>& installed_by) {
78 // We restrict by !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) because a
79 // sideloaded heapprofd should not be restricted by this. Do note though that,
80 // at the moment, there isn't really a way to sideload a functioning heapprofd
81 // onto user builds.
82 #if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) || \
83     !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
84   base::ignore_result(ds_config);
85   base::ignore_result(uid);
86   base::ignore_result(installed_by);
87   return true;
88 #else
89   std::string build_type = base::GetAndroidProp("ro.build.type");
90   return CanProfileAndroid(ds_config, uid, installed_by, build_type,
91                            "/data/system/packages.list");
92 #endif
93 }
94 
CanProfileAndroid(const DataSourceConfig & ds_config,uint64_t uid,const std::vector<std::string> & installed_by,const std::string & build_type,const std::string & packages_list_path)95 bool CanProfileAndroid(const DataSourceConfig& ds_config,
96                        uint64_t uid,
97                        const std::vector<std::string>& installed_by,
98                        const std::string& build_type,
99                        const std::string& packages_list_path) {
100   // These constants are replicated from libcutils android_filesystem_config.h,
101   // to allow for building and testing the profilers outside the android tree.
102   constexpr auto kAidUserOffset = 100000;      // AID_USER_OFFSET
103   constexpr auto kAidAppStart = 10000;         // AID_APP_START
104   constexpr auto kAidAppEnd = 19999;           // AID_APP_END
105   constexpr auto kAidSdkSandboxStart = 20000;  // AID_SDK_SANDBOX_PROCESS_START
106   constexpr auto kAidSdkSandboxEnd = 29999;    // AID_SDK_SANDBOX_PROCESS_END
107   constexpr auto kAidIsolatedStart = 90000;    // AID_ISOLATED_START
108   constexpr auto kAidIsolatedEnd = 99999;      // AID_ISOLATED_END
109 
110   if (!build_type.empty() && build_type != "user") {
111     return true;
112   }
113 
114   bool trusted_initiator = ds_config.session_initiator() ==
115                            DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM;
116 
117   uint64_t uid_without_profile = uid % kAidUserOffset;
118   uint64_t uid_for_lookup = 0;
119   if (uid_without_profile < kAidAppStart) {
120     // Platform processes are considered profileable by the platform itself.
121     // This includes platform UIDs from other profiles, e.g. "u10_system".
122     // It's possible that this is an app (e.g. com.android.settings runs as
123     // AID_SYSTEM), but we will skip checking packages.list for the profileable
124     // manifest flags, as running under a platform UID is considered sufficient.
125     // Minor consequence: shell cannot profile platform apps, even if their
126     // manifest flags opt into profiling from shell. Resolving this would
127     // require definitively disambiguating native processes from apps if both
128     // can run as the same platform UID.
129     return trusted_initiator;
130 
131   } else if (uid_without_profile >= kAidAppStart &&
132              uid_without_profile <= kAidAppEnd) {
133     // normal app
134     uid_for_lookup = uid_without_profile;
135 
136   } else if (uid_without_profile >= kAidSdkSandboxStart &&
137              uid_without_profile <= kAidSdkSandboxEnd) {
138     // sdk sandbox process, has deterministic mapping to corresponding app
139     uint64_t sdk_sandbox_offset = kAidSdkSandboxStart - kAidAppStart;
140     uid_for_lookup = uid_without_profile - sdk_sandbox_offset;
141 
142   } else if (uid_without_profile >= kAidIsolatedStart &&
143              uid_without_profile <= kAidIsolatedEnd) {
144     // Isolated process. Such processes run under random UIDs and have no
145     // straightforward link to the original app's UID without consulting
146     // system_server. So we have to perform a very conservative check - if *all*
147     // packages are profileable, then any isolated process must be profileable
148     // as well, regardless of which package it's running for (which might not
149     // even be the package in which the service was defined).
150     // TODO(rsavitski): find a way for the platform to tell native services
151     // about isolated<->app relations.
152     return trusted_initiator &&
153            AllPackagesProfileableByTrustedInitiator(packages_list_path);
154 
155   } else {
156     // disallow everything else on release builds
157     return false;
158   }
159 
160   std::optional<Package> pkg =
161       FindInPackagesList(uid_for_lookup, packages_list_path);
162 
163   if (!pkg)
164     return false;
165 
166   // check installer constraint if given
167   if (!installed_by.empty()) {
168     if (pkg->installed_by.empty()) {
169       PERFETTO_ELOG("Cannot parse installer from packages.list");
170       return false;
171     }
172     if (std::find(installed_by.cbegin(), installed_by.cend(),
173                   pkg->installed_by) == installed_by.cend()) {
174       // not installed by one of the requested origins
175       return false;
176     }
177   }
178 
179   switch (ds_config.session_initiator()) {
180     case DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED:
181       return pkg->profileable_from_shell || pkg->debuggable;
182     case DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM:
183       return pkg->profileable || pkg->debuggable;
184   }
185   return false;
186 }
187 
188 }  // namespace profiling
189 }  // namespace perfetto
190