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