blob: 274a1b36d4d1a0ece6db8d6729a64b4bb2b7698c [file] [log] [blame]
#include <errno.h>
#include <sched.h>
#include <sys/types.h>
#include <unistd.h>
#include <condition_variable>
#include <cstdlib>
#include <mutex>
#include <thread>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
namespace {
const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
} // anonymous namespace
TEST(DISABLED_PerformanceTest, SetCpuPartition) {
int error;
// Test setting the the partition for the current task.
error = dvrSetCpuPartition(0, "/application/background");
EXPECT_EQ(0, error);
error = dvrSetCpuPartition(0, "/application/performance");
EXPECT_EQ(0, error);
// Test setting the partition for one of our tasks.
bool done = false;
pid_t task_id = 0;
std::mutex mutex;
std::condition_variable done_condition, id_condition;
std::thread thread([&] {
std::unique_lock<std::mutex> lock(mutex);
task_id = gettid();
id_condition.notify_one();
done_condition.wait(lock, [&done] { return done; });
});
{
std::unique_lock<std::mutex> lock(mutex);
id_condition.wait(lock, [&task_id] { return task_id != 0; });
}
EXPECT_NE(0, task_id);
error = dvrSetCpuPartition(task_id, "/application");
EXPECT_EQ(0, error);
{
std::lock_guard<std::mutex> lock(mutex);
done = true;
done_condition.notify_one();
}
thread.join();
// Test setting the partition for a task that isn't valid using
// the task id of the thread that we just joined. Technically the
// id could wrap around by the time we get here, but this is
// extremely unlikely.
error = dvrSetCpuPartition(task_id, "/application");
EXPECT_EQ(-EINVAL, error);
// Test setting the partition for a task that doesn't belong to us.
error = dvrSetCpuPartition(1, "/application");
EXPECT_EQ(-EINVAL, error);
// Test setting the partition to one that doesn't exist.
error = dvrSetCpuPartition(0, "/foobar");
EXPECT_EQ(-ENOENT, error);
}
TEST(PerformanceTest, SetSchedulerClass) {
int error;
// TODO(eieio): Test all supported scheduler classes and priority levels.
error = dvrSetSchedulerClass(0, "background");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
error = dvrSetSchedulerClass(0, "audio:low");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
error = dvrSetSchedulerClass(0, "normal");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
error = dvrSetSchedulerClass(0, "foobar");
EXPECT_EQ(-EINVAL, error);
}
// This API mirrors SetSchedulerClass for now. Replace with with a more specific
// test once the policy API is fully implemented.
TEST(PerformanceTest, SetSchedulerPolicy) {
int error;
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
error = dvrSetSchedulerPolicy(0, "foobar");
EXPECT_EQ(-EINVAL, error);
}
TEST(PerformanceTest, SchedulerClassResetOnFork) {
int error;
error = dvrSetSchedulerClass(0, "graphics:high");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
int scheduler = -1;
std::thread thread([&]() { scheduler = sched_getscheduler(0); });
thread.join();
EXPECT_EQ(SCHED_NORMAL, scheduler);
// Return to SCHED_NORMAL.
error = dvrSetSchedulerClass(0, "normal");
EXPECT_EQ(0, error);
EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
}
TEST(PerformanceTest, GetCpuPartition) {
int error;
char partition[PATH_MAX + 1];
error = dvrSetCpuPartition(0, "/");
ASSERT_EQ(0, error);
error = dvrGetCpuPartition(0, partition, sizeof(partition));
EXPECT_EQ(0, error);
EXPECT_EQ("/", std::string(partition));
error = dvrSetCpuPartition(0, "/application");
EXPECT_EQ(0, error);
error = dvrGetCpuPartition(0, partition, sizeof(partition));
EXPECT_EQ(0, error);
EXPECT_EQ("/application", std::string(partition));
// Test passing a buffer that is too short.
error = dvrGetCpuPartition(0, partition, 5);
EXPECT_EQ(-ENOBUFS, error);
// Test getting the partition for a task that doesn't belong to us.
error = dvrGetCpuPartition(1, partition, sizeof(partition));
EXPECT_EQ(-EINVAL, error);
// Test passing a nullptr value for partition buffer.
error = dvrGetCpuPartition(0, nullptr, sizeof(partition));
EXPECT_EQ(-EINVAL, error);
}
TEST(PerformanceTest, Permissions) {
int error;
const int original_uid = getuid();
const int original_gid = getgid();
int trusted_uid = -1;
// See if the environment variable GTEST_TRUSTED_UID is set. If it is enable
// testing the ActivityManager trusted uid permission checks using that uid.
const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable);
if (trusted_uid_env)
trusted_uid = std::atoi(trusted_uid_env);
ASSERT_EQ(AID_ROOT, original_uid)
<< "This test must run as root to function correctly!";
// Test unprivileged policies on a task that does not belong to this process.
// Use the init process (task_id=1) as the target.
error = dvrSetSchedulerPolicy(1, "batch");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(1, "background");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(1, "foreground");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(1, "normal");
EXPECT_EQ(-EINVAL, error);
// Switch the uid/gid to an id that should not have permission to access any
// privileged actions.
ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
<< "Failed to set gid: " << strerror(errno);
ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
<< "Failed to set uid: " << strerror(errno);
// Unprivileged policies.
error = dvrSetSchedulerPolicy(0, "batch");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "foreground");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
// Privileged policies.
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:system:arp");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:app:render");
EXPECT_EQ(-EINVAL, error);
// uid=AID_SYSTEM / gid=AID_NOBODY
ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
<< "Failed to restore uid: " << strerror(errno);
ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1))
<< "Failed to set uid: " << strerror(errno);
// Unprivileged policies.
error = dvrSetSchedulerPolicy(0, "batch");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "foreground");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
// Privileged policies.
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "vr:system:arp");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "vr:app:render");
EXPECT_EQ(0, error);
// uid=AID_NOBODY / gid=AID_SYSTEM
ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
<< "Failed to restore uid: " << strerror(errno);
ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
<< "Failed to restore gid: " << strerror(errno);
ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1))
<< "Failed to set gid: " << strerror(errno);
ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1))
<< "Failed to set uid: " << strerror(errno);
// Unprivileged policies.
error = dvrSetSchedulerPolicy(0, "batch");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "foreground");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
// Privileged policies.
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "vr:system:arp");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "vr:app:render");
EXPECT_EQ(0, error);
// uid=AID_GRAPHICS / gid=AID_NOBODY
ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
<< "Failed to restore uid: " << strerror(errno);
ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
<< "Failed to restore gid: " << strerror(errno);
ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
<< "Failed to set gid: " << strerror(errno);
ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1))
<< "Failed to set uid: " << strerror(errno);
// Unprivileged policies.
error = dvrSetSchedulerPolicy(0, "batch");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "foreground");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
// Privileged policies.
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:system:arp");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:app:render");
EXPECT_EQ(-EINVAL, error);
// uid=AID_NOBODY / gid=AID_GRAPHICS
ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
<< "Failed to restore uid: " << strerror(errno);
ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
<< "Failed to restore gid: " << strerror(errno);
ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1))
<< "Failed to set gid: " << strerror(errno);
ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
<< "Failed to set uid: " << strerror(errno);
// Unprivileged policies.
error = dvrSetSchedulerPolicy(0, "batch");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "foreground");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
// Privileged policies.
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:system:arp");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:app:render");
EXPECT_EQ(-EINVAL, error);
if (trusted_uid != -1) {
// uid=<trusted uid> / gid=AID_NOBODY
ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
<< "Failed to restore uid: " << strerror(errno);
ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
<< "Failed to restore gid: " << strerror(errno);
ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
<< "Failed to set gid: " << strerror(errno);
ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1))
<< "Failed to set uid: " << strerror(errno);
// Unprivileged policies.
error = dvrSetSchedulerPolicy(0, "batch");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "background");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "foreground");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "normal");
EXPECT_EQ(0, error);
// Privileged policies.
error = dvrSetSchedulerPolicy(0, "audio:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "vr:system:arp");
EXPECT_EQ(0, error);
error = dvrSetSchedulerPolicy(0, "vr:app:render");
EXPECT_EQ(0, error);
}
// Restore original effective uid/gid.
ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
<< "Failed to restore gid: " << strerror(errno);
ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
<< "Failed to restore uid: " << strerror(errno);
}