blob: 8ab0b42a650df7f1dc73575014ca24dea7c8dc59 [file] [log] [blame]
/*
* 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 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;
}
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