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 "perfetto/ext/base/file_utils.h"
20 #include "perfetto/ext/base/string_splitter.h"
21 #include "perfetto/tracing/core/data_source_config.h"
22 
23 #include "perfetto/tracing/core/forward_decls.h"
24 #include "src/traced/probes/packages_list/packages_list_parser.h"
25 
26 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
27 #include <sys/system_properties.h>
28 #endif
29 
30 namespace perfetto {
31 namespace profiling {
32 
CanProfile(const DataSourceConfig & ds_config,uint64_t uid,const std::vector<std::string> & installed_by)33 bool CanProfile(const DataSourceConfig& ds_config,
34                 uint64_t uid,
35                 const std::vector<std::string>& installed_by) {
36 // We restrict by !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) because a
37 // sideloaded heapprofd should not be restricted by this. Do note though that,
38 // at the moment, there isn't really a way to sideload a functioning heapprofd
39 // onto user builds.
40 #if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) || \
41     !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
42   base::ignore_result(ds_config);
43   base::ignore_result(uid);
44   base::ignore_result(installed_by);
45   return true;
46 #else
47   char buf[PROP_VALUE_MAX + 1] = {};
48   int ret = __system_property_get("ro.build.type", buf);
49   PERFETTO_CHECK(ret >= 0);
50   return CanProfileAndroid(ds_config, uid, installed_by, std::string(buf),
51                            "/data/system/packages.list");
52 #endif
53 }
54 
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)55 bool CanProfileAndroid(const DataSourceConfig& ds_config,
56                        uint64_t uid,
57                        const std::vector<std::string>& installed_by,
58                        const std::string& build_type,
59                        const std::string& packages_list_path) {
60   // These are replicated constants from libcutils android_filesystem_config.h
61   constexpr auto kAidAppStart = 10000;     // AID_APP_START
62   constexpr auto kAidAppEnd = 19999;       // AID_APP_END
63   constexpr auto kAidUserOffset = 100000;  // AID_USER_OFFSET
64 
65   if (build_type != "user") {
66     return true;
67   }
68 
69   uint64_t uid_without_profile = uid % kAidUserOffset;
70   if (uid_without_profile < kAidAppStart || kAidAppEnd < uid_without_profile) {
71     // TODO(fmayer): relax this.
72     return false;  // no native services on user.
73   }
74 
75   std::string content;
76   if (!base::ReadFile(packages_list_path, &content)) {
77     PERFETTO_ELOG("Failed to read %s.", packages_list_path.c_str());
78     return false;
79   }
80   for (base::StringSplitter ss(std::move(content), '\n'); ss.Next();) {
81     Package pkg;
82     if (!ReadPackagesListLine(ss.cur_token(), &pkg)) {
83       PERFETTO_ELOG("Failed to parse packages.list.");
84       return false;
85     }
86     if (pkg.uid != uid_without_profile)
87       continue;
88     if (!installed_by.empty()) {
89       if (pkg.installed_by.empty()) {
90         PERFETTO_ELOG(
91             "installed_by given in TraceConfig, but cannot parse "
92             "installer from packages.list.");
93         return false;
94       }
95       if (std::find(installed_by.cbegin(), installed_by.cend(),
96                     pkg.installed_by) == installed_by.cend()) {
97         return false;
98       }
99     }
100     switch (ds_config.session_initiator()) {
101       case DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED:
102         return pkg.profileable_from_shell || pkg.debuggable;
103       case DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM:
104         return pkg.profileable || pkg.debuggable;
105     }
106   }
107   // Did not find package.
108   return false;
109 }
110 
111 }  // namespace profiling
112 }  // namespace perfetto
113