aboutsummaryrefslogtreecommitdiff
path: root/src/profiling/common/producer_support.cc
blob: 544d3c5a29d94bef3a41c6945088b2971cf65edd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/profiling/common/producer_support.h"

#include "perfetto/ext/base/android_utils.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/optional.h"
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "src/traced/probes/packages_list/packages_list_parser.h"

namespace perfetto {
namespace profiling {

namespace {
base::Optional<Package> FindInPackagesList(
    uint64_t lookup_uid,
    const std::string& packages_list_path) {
  std::string content;
  if (!base::ReadFile(packages_list_path, &content)) {
    PERFETTO_ELOG("Failed to read %s", packages_list_path.c_str());
    return base::nullopt;
  }
  for (base::StringSplitter ss(std::move(content), '\n'); ss.Next();) {
    Package pkg;
    if (!ReadPackagesListLine(ss.cur_token(), &pkg)) {
      PERFETTO_ELOG("Failed to parse packages.list");
      return base::nullopt;
    }

    if (pkg.uid == lookup_uid) {
      return std::move(pkg);  // -Wreturn-std-move-in-c++11
    }
  }
  return base::nullopt;
}

bool AllPackagesProfileableByTrustedInitiator(
    const std::string& packages_list_path) {
  std::string content;
  if (!base::ReadFile(packages_list_path, &content)) {
    PERFETTO_ELOG("Failed to read %s", packages_list_path.c_str());
    return false;
  }
  bool ret = true;
  for (base::StringSplitter ss(std::move(content), '\n'); ss.Next();) {
    Package pkg;
    if (!ReadPackagesListLine(ss.cur_token(), &pkg)) {
      PERFETTO_ELOG("Failed to parse packages.list");
      return false;
    }

    ret = ret && (pkg.profileable || pkg.debuggable);
  }
  return ret;
}

}  // namespace

bool CanProfile(const DataSourceConfig& ds_config,
                uint64_t uid,
                const std::vector<std::string>& installed_by) {
// We restrict by !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) because a
// sideloaded heapprofd should not be restricted by this. Do note though that,
// at the moment, there isn't really a way to sideload a functioning heapprofd
// onto user builds.
#if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) || \
    !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  base::ignore_result(ds_config);
  base::ignore_result(uid);
  base::ignore_result(installed_by);
  return true;
#else
  std::string build_type = base::GetAndroidProp("ro.build.type");
  return CanProfileAndroid(ds_config, uid, installed_by, build_type,
                           "/data/system/packages.list");
#endif
}

bool 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) {
  // These constants are replicated from libcutils android_filesystem_config.h,
  // to allow for building and testing the profilers outside the android tree.
  constexpr auto kAidSystem = 1000;           // AID_SYSTEM
  constexpr auto kAidUserOffset = 100000;     // AID_USER_OFFSET
  constexpr auto kAidAppStart = 10000;        // AID_APP_START
  constexpr auto kAidAppEnd = 19999;          // AID_APP_END
  constexpr auto kAidSdkSandboxStart = 20000; // AID_SDK_SANDBOX_PROCESS_START
  constexpr auto kAidSdkSandboxEnd = 29999;   // AID_SDK_SANDBOX_PROCESS_END
  constexpr auto kAidIsolatedStart = 90000;   // AID_ISOLATED_START
  constexpr auto kAidIsolatedEnd = 99999;     // AID_ISOLATED_END

  if (!build_type.empty() && build_type != "user") {
    return true;
  }

  // TODO(b/217368496): remove this.
  if (uid == kAidSystem) {
    return ds_config.session_initiator() ==
      DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM;
  }

  uint64_t uid_without_profile = uid % kAidUserOffset;
  uint64_t uid_for_lookup = 0;
  if (uid_without_profile >= kAidAppStart &&
      uid_without_profile <= kAidAppEnd) {
    // normal app
    uid_for_lookup = uid_without_profile;

  } else if (uid_without_profile >= kAidSdkSandboxStart &&
             uid_without_profile <= kAidSdkSandboxEnd) {
    // sdk sandbox process, has deterministic mapping to corresponding app
    uint64_t sdk_sandbox_offset = kAidSdkSandboxStart - kAidAppStart;
    uid_for_lookup = uid_without_profile - sdk_sandbox_offset;

  } else if (uid_without_profile >= kAidIsolatedStart &&
             uid_without_profile <= kAidIsolatedEnd) {
    // Isolated process. Such processes run under random UIDs and have no
    // straightforward link to the original app's UID without consulting
    // system_server. So we have to perform a very conservative check - if *all*
    // packages are profileable, then any isolated process must be profileable
    // as well, regardless of which package it's running for (which might not
    // even be the package in which the service was defined).
    // TODO(rsavitski): find a way for the platform to tell native services
    // about isolated<->app relations.
    bool trusted_initiator = ds_config.session_initiator() ==
                             DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM;
    return trusted_initiator &&
           AllPackagesProfileableByTrustedInitiator(packages_list_path);

  } else {
    // disallow everything else on release builds
    return false;
  }

  base::Optional<Package> pkg =
      FindInPackagesList(uid_for_lookup, packages_list_path);

  if (!pkg)
    return false;

  // check installer constraint if given
  if (!installed_by.empty()) {
    if (pkg->installed_by.empty()) {
      PERFETTO_ELOG("Cannot parse installer from packages.list");
      return false;
    }
    if (std::find(installed_by.cbegin(), installed_by.cend(),
                  pkg->installed_by) == installed_by.cend()) {
      // not installed by one of the requested origins
      return false;
    }
  }

  switch (ds_config.session_initiator()) {
    case DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED:
      return pkg->profileable_from_shell || pkg->debuggable;
    case DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM:
      return pkg->profileable || pkg->debuggable;
  }
  return false;
}

}  // namespace profiling
}  // namespace perfetto