1#include <errno.h>
2#include <sched.h>
3#include <stdio.h>
4#include <sys/types.h>
5#include <unistd.h>
6
7#include <condition_variable>
8#include <cstdlib>
9#include <iostream>
10#include <mutex>
11#include <sstream>
12#include <thread>
13#include <utility>
14
15#include <android-base/unique_fd.h>
16#include <dvr/performance_client_api.h>
17#include <gtest/gtest.h>
18#include <private/android_filesystem_config.h>
19
20#include "stdio_filebuf.h"
21#include "string_trim.h"
22#include "unique_file.h"
23
24using android::dvr::Trim;
25using android::dvr::UniqueFile;
26using android::dvr::stdio_filebuf;
27
28namespace {
29
30const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
31
32const char kProcBase[] = "/proc";
33
34std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id,
35                                        const std::string& name) {
36  std::ostringstream stream;
37  stream << kProcBase << "/" << task_id << "/" << name;
38
39  UniqueFile file{fopen(stream.str().c_str(), "r")};
40  const int error = file ? 0 : errno;
41  return {std::move(file), error};
42}
43
44std::string GetTaskCpuSet(pid_t task_id) {
45  int error;
46  UniqueFile file;
47
48  std::tie(file, error) = OpenTaskFile(task_id, "cpuset");
49  if (!file)
50    return std::string("errno:") + strerror(error);
51
52  stdio_filebuf<char> filebuf(file.get());
53  std::istream file_stream(&filebuf);
54
55  std::string line;
56  std::getline(file_stream, line);
57  return Trim(line);
58}
59
60}  // anonymous namespace
61
62TEST(PerformanceTest, SetCpuPartition) {
63  int error;
64
65  // Test setting the the partition for the current task.
66  error = dvrSetCpuPartition(0, "/application/background");
67  EXPECT_EQ(0, error);
68
69  error = dvrSetCpuPartition(0, "/application/performance");
70  EXPECT_EQ(0, error);
71
72  // Test setting the partition for one of our tasks.
73  bool done = false;
74  pid_t task_id = 0;
75  std::mutex mutex;
76  std::condition_variable done_condition, id_condition;
77
78  std::thread thread([&] {
79    std::unique_lock<std::mutex> lock(mutex);
80
81    task_id = gettid();
82    id_condition.notify_one();
83
84    done_condition.wait(lock, [&done] { return done; });
85  });
86
87  {
88    std::unique_lock<std::mutex> lock(mutex);
89    id_condition.wait(lock, [&task_id] { return task_id != 0; });
90  }
91  EXPECT_NE(0, task_id);
92
93  error = dvrSetCpuPartition(task_id, "/application");
94  EXPECT_EQ(0, error);
95
96  {
97    std::lock_guard<std::mutex> lock(mutex);
98    done = true;
99    done_condition.notify_one();
100  }
101  thread.join();
102
103  // Test setting the partition for a task that doesn't belong to us.
104  error = dvrSetCpuPartition(1, "/application");
105  EXPECT_EQ(-EINVAL, error);
106
107  // Test setting the partition to one that doesn't exist.
108  error = dvrSetCpuPartition(0, "/foobar");
109  EXPECT_EQ(-ENOENT, error);
110
111  // Set the test back to the root partition.
112  error = dvrSetCpuPartition(0, "/");
113  EXPECT_EQ(0, error);
114}
115
116TEST(PerformanceTest, SetSchedulerClass) {
117  int error;
118
119  // TODO(eieio): Test all supported scheduler classes and priority levels.
120
121  error = dvrSetSchedulerClass(0, "background");
122  EXPECT_EQ(0, error);
123  EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
124
125  error = dvrSetSchedulerClass(0, "audio:low");
126  EXPECT_EQ(0, error);
127  EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
128
129  error = dvrSetSchedulerClass(0, "normal");
130  EXPECT_EQ(0, error);
131  EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
132
133  error = dvrSetSchedulerClass(0, "foobar");
134  EXPECT_EQ(-EINVAL, error);
135}
136
137TEST(PerformanceTest, SetSchedulerPolicy) {
138  int error;
139
140  error = dvrSetSchedulerPolicy(0, "background");
141  EXPECT_EQ(0, error);
142  EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
143
144  error = dvrSetSchedulerPolicy(0, "audio:low");
145  EXPECT_EQ(0, error);
146  EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
147
148  error = dvrSetSchedulerPolicy(0, "normal");
149  EXPECT_EQ(0, error);
150  EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
151
152  error = dvrSetSchedulerPolicy(0, "foobar");
153  EXPECT_EQ(-EINVAL, error);
154
155  // Set the test back to the root partition.
156  error = dvrSetCpuPartition(0, "/");
157  EXPECT_EQ(0, error);
158
159  const std::string original_cpuset = GetTaskCpuSet(gettid());
160  EXPECT_EQ("/", original_cpuset);
161
162  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
163  EXPECT_EQ(0, error);
164  EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
165
166  const std::string new_cpuset = GetTaskCpuSet(gettid());
167  EXPECT_NE(original_cpuset, new_cpuset);
168
169  // The cpuset for the thread group is now new_cpuset. Scheduler profiles that
170  // do not specify a cpuset should not change the cpuset of a thread, except to
171  // restore it to the thread group cpuset.
172  std::string thread_original_cpuset;
173  std::string thread_new_cpuset;
174  std::string thread_final_cpuset;
175
176  std::thread thread{
177      [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() {
178        thread_original_cpuset = GetTaskCpuSet(gettid());
179
180        int error = dvrSetSchedulerPolicy(0, "vr:app:render");
181        EXPECT_EQ(0, error);
182
183        thread_new_cpuset = GetTaskCpuSet(gettid());
184
185        error = dvrSetSchedulerPolicy(0, "normal");
186        EXPECT_EQ(0, error);
187
188        thread_final_cpuset = GetTaskCpuSet(gettid());
189      }};
190  thread.join();
191
192  EXPECT_EQ(new_cpuset, thread_original_cpuset);
193  EXPECT_NE(new_cpuset, thread_new_cpuset);
194  EXPECT_EQ(new_cpuset, thread_final_cpuset);
195
196  error = dvrSetCpuPartition(0, original_cpuset.c_str());
197  EXPECT_EQ(0, error);
198}
199
200TEST(PerformanceTest, SchedulerClassResetOnFork) {
201  int error;
202
203  error = dvrSetSchedulerClass(0, "graphics:high");
204  EXPECT_EQ(0, error);
205  EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
206
207  int scheduler = -1;
208  std::thread thread([&]() { scheduler = sched_getscheduler(0); });
209  thread.join();
210
211  EXPECT_EQ(SCHED_NORMAL, scheduler);
212
213  // Return to SCHED_NORMAL.
214  error = dvrSetSchedulerClass(0, "normal");
215  EXPECT_EQ(0, error);
216  EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
217}
218
219TEST(PerformanceTest, GetCpuPartition) {
220  int error;
221  char partition[PATH_MAX + 1];
222
223  error = dvrSetCpuPartition(0, "/");
224  ASSERT_EQ(0, error);
225
226  error = dvrGetCpuPartition(0, partition, sizeof(partition));
227  EXPECT_EQ(0, error);
228  EXPECT_EQ("/", std::string(partition));
229
230  error = dvrSetCpuPartition(0, "/application");
231  EXPECT_EQ(0, error);
232
233  error = dvrGetCpuPartition(0, partition, sizeof(partition));
234  EXPECT_EQ(0, error);
235  EXPECT_EQ("/application", std::string(partition));
236
237  // Test passing a buffer that is too short.
238  error = dvrGetCpuPartition(0, partition, 5);
239  EXPECT_EQ(-ENOBUFS, error);
240
241  // Test getting the partition for a task that doesn't belong to us.
242  error = dvrGetCpuPartition(1, partition, sizeof(partition));
243  EXPECT_EQ(-EINVAL, error);
244
245  // Test passing a nullptr value for partition buffer.
246  error = dvrGetCpuPartition(0, nullptr, sizeof(partition));
247  EXPECT_EQ(-EINVAL, error);
248}
249
250TEST(PerformanceTest, Permissions) {
251  int error;
252
253  const int original_uid = getuid();
254  const int original_gid = getgid();
255  int trusted_uid = -1;
256
257  // See if the environment variable GTEST_TRUSTED_UID is set. If it is enable
258  // testing the ActivityManager trusted uid permission checks using that uid.
259  const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable);
260  if (trusted_uid_env)
261    trusted_uid = std::atoi(trusted_uid_env);
262
263  ASSERT_EQ(AID_ROOT, original_uid)
264      << "This test must run as root to function correctly!";
265
266  // Test unprivileged policies on a task that does not belong to this process.
267  // Use the init process (task_id=1) as the target.
268  error = dvrSetSchedulerPolicy(1, "batch");
269  EXPECT_EQ(-EINVAL, error);
270  error = dvrSetSchedulerPolicy(1, "background");
271  EXPECT_EQ(-EINVAL, error);
272  error = dvrSetSchedulerPolicy(1, "foreground");
273  EXPECT_EQ(-EINVAL, error);
274  error = dvrSetSchedulerPolicy(1, "normal");
275  EXPECT_EQ(-EINVAL, error);
276
277  // Switch the uid/gid to an id that should not have permission to access any
278  // privileged actions.
279  ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
280      << "Failed to set gid: " << strerror(errno);
281  ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
282      << "Failed to set uid: " << strerror(errno);
283
284  // Unprivileged policies.
285  error = dvrSetSchedulerPolicy(0, "batch");
286  EXPECT_EQ(0, error);
287  error = dvrSetSchedulerPolicy(0, "background");
288  EXPECT_EQ(0, error);
289  error = dvrSetSchedulerPolicy(0, "foreground");
290  EXPECT_EQ(0, error);
291  error = dvrSetSchedulerPolicy(0, "normal");
292  EXPECT_EQ(0, error);
293
294  // Privileged policies.
295  error = dvrSetSchedulerPolicy(0, "audio:low");
296  EXPECT_EQ(-EINVAL, error);
297  error = dvrSetSchedulerPolicy(0, "audio:high");
298  EXPECT_EQ(-EINVAL, error);
299  error = dvrSetSchedulerPolicy(0, "graphics");
300  EXPECT_EQ(-EINVAL, error);
301  error = dvrSetSchedulerPolicy(0, "graphics:low");
302  EXPECT_EQ(-EINVAL, error);
303  error = dvrSetSchedulerPolicy(0, "graphics:high");
304  EXPECT_EQ(-EINVAL, error);
305  error = dvrSetSchedulerPolicy(0, "sensors");
306  EXPECT_EQ(-EINVAL, error);
307  error = dvrSetSchedulerPolicy(0, "sensors:low");
308  EXPECT_EQ(-EINVAL, error);
309  error = dvrSetSchedulerPolicy(0, "sensors:high");
310  EXPECT_EQ(-EINVAL, error);
311  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
312  EXPECT_EQ(-EINVAL, error);
313  error = dvrSetSchedulerPolicy(0, "vr:app:render");
314  EXPECT_EQ(-EINVAL, error);
315
316  // uid=AID_SYSTEM / gid=AID_NOBODY
317  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
318      << "Failed to restore uid: " << strerror(errno);
319  ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1))
320      << "Failed to set uid: " << strerror(errno);
321
322  // Unprivileged policies.
323  error = dvrSetSchedulerPolicy(0, "batch");
324  EXPECT_EQ(0, error);
325  error = dvrSetSchedulerPolicy(0, "background");
326  EXPECT_EQ(0, error);
327  error = dvrSetSchedulerPolicy(0, "foreground");
328  EXPECT_EQ(0, error);
329  error = dvrSetSchedulerPolicy(0, "normal");
330  EXPECT_EQ(0, error);
331
332  // Privileged policies.
333  error = dvrSetSchedulerPolicy(0, "audio:low");
334  EXPECT_EQ(0, error);
335  error = dvrSetSchedulerPolicy(0, "audio:high");
336  EXPECT_EQ(0, error);
337  error = dvrSetSchedulerPolicy(0, "graphics");
338  EXPECT_EQ(0, error);
339  error = dvrSetSchedulerPolicy(0, "graphics:low");
340  EXPECT_EQ(0, error);
341  error = dvrSetSchedulerPolicy(0, "graphics:high");
342  EXPECT_EQ(0, error);
343  error = dvrSetSchedulerPolicy(0, "sensors");
344  EXPECT_EQ(0, error);
345  error = dvrSetSchedulerPolicy(0, "sensors:low");
346  EXPECT_EQ(0, error);
347  error = dvrSetSchedulerPolicy(0, "sensors:high");
348  EXPECT_EQ(0, error);
349  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
350  EXPECT_EQ(0, error);
351  error = dvrSetSchedulerPolicy(0, "vr:app:render");
352  EXPECT_EQ(0, error);
353
354  // uid=AID_NOBODY / gid=AID_SYSTEM
355  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
356      << "Failed to restore uid: " << strerror(errno);
357  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
358      << "Failed to restore gid: " << strerror(errno);
359  ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1))
360      << "Failed to set gid: " << strerror(errno);
361  ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1))
362      << "Failed to set uid: " << strerror(errno);
363
364  // Unprivileged policies.
365  error = dvrSetSchedulerPolicy(0, "batch");
366  EXPECT_EQ(0, error);
367  error = dvrSetSchedulerPolicy(0, "background");
368  EXPECT_EQ(0, error);
369  error = dvrSetSchedulerPolicy(0, "foreground");
370  EXPECT_EQ(0, error);
371  error = dvrSetSchedulerPolicy(0, "normal");
372  EXPECT_EQ(0, error);
373
374  // Privileged policies.
375  error = dvrSetSchedulerPolicy(0, "audio:low");
376  EXPECT_EQ(0, error);
377  error = dvrSetSchedulerPolicy(0, "audio:high");
378  EXPECT_EQ(0, error);
379  error = dvrSetSchedulerPolicy(0, "graphics");
380  EXPECT_EQ(0, error);
381  error = dvrSetSchedulerPolicy(0, "graphics:low");
382  EXPECT_EQ(0, error);
383  error = dvrSetSchedulerPolicy(0, "graphics:high");
384  EXPECT_EQ(0, error);
385  error = dvrSetSchedulerPolicy(0, "sensors");
386  EXPECT_EQ(0, error);
387  error = dvrSetSchedulerPolicy(0, "sensors:low");
388  EXPECT_EQ(0, error);
389  error = dvrSetSchedulerPolicy(0, "sensors:high");
390  EXPECT_EQ(0, error);
391  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
392  EXPECT_EQ(0, error);
393  error = dvrSetSchedulerPolicy(0, "vr:app:render");
394  EXPECT_EQ(0, error);
395
396  // uid=AID_GRAPHICS / gid=AID_NOBODY
397  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
398      << "Failed to restore uid: " << strerror(errno);
399  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
400      << "Failed to restore gid: " << strerror(errno);
401  ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
402      << "Failed to set gid: " << strerror(errno);
403  ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1))
404      << "Failed to set uid: " << strerror(errno);
405
406  // Unprivileged policies.
407  error = dvrSetSchedulerPolicy(0, "batch");
408  EXPECT_EQ(0, error);
409  error = dvrSetSchedulerPolicy(0, "background");
410  EXPECT_EQ(0, error);
411  error = dvrSetSchedulerPolicy(0, "foreground");
412  EXPECT_EQ(0, error);
413  error = dvrSetSchedulerPolicy(0, "normal");
414  EXPECT_EQ(0, error);
415
416  // Privileged policies.
417  error = dvrSetSchedulerPolicy(0, "audio:low");
418  EXPECT_EQ(-EINVAL, error);
419  error = dvrSetSchedulerPolicy(0, "audio:high");
420  EXPECT_EQ(-EINVAL, error);
421  error = dvrSetSchedulerPolicy(0, "graphics");
422  EXPECT_EQ(0, error);
423  error = dvrSetSchedulerPolicy(0, "graphics:low");
424  EXPECT_EQ(0, error);
425  error = dvrSetSchedulerPolicy(0, "graphics:high");
426  EXPECT_EQ(0, error);
427  error = dvrSetSchedulerPolicy(0, "sensors");
428  EXPECT_EQ(-EINVAL, error);
429  error = dvrSetSchedulerPolicy(0, "sensors:low");
430  EXPECT_EQ(-EINVAL, error);
431  error = dvrSetSchedulerPolicy(0, "sensors:high");
432  EXPECT_EQ(-EINVAL, error);
433  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
434  EXPECT_EQ(-EINVAL, error);
435  error = dvrSetSchedulerPolicy(0, "vr:app:render");
436  EXPECT_EQ(-EINVAL, error);
437
438  // uid=AID_NOBODY / gid=AID_GRAPHICS
439  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
440      << "Failed to restore uid: " << strerror(errno);
441  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
442      << "Failed to restore gid: " << strerror(errno);
443  ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1))
444      << "Failed to set gid: " << strerror(errno);
445  ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
446      << "Failed to set uid: " << strerror(errno);
447
448  // Unprivileged policies.
449  error = dvrSetSchedulerPolicy(0, "batch");
450  EXPECT_EQ(0, error);
451  error = dvrSetSchedulerPolicy(0, "background");
452  EXPECT_EQ(0, error);
453  error = dvrSetSchedulerPolicy(0, "foreground");
454  EXPECT_EQ(0, error);
455  error = dvrSetSchedulerPolicy(0, "normal");
456  EXPECT_EQ(0, error);
457
458  // Privileged policies.
459  error = dvrSetSchedulerPolicy(0, "audio:low");
460  EXPECT_EQ(-EINVAL, error);
461  error = dvrSetSchedulerPolicy(0, "audio:high");
462  EXPECT_EQ(-EINVAL, error);
463  error = dvrSetSchedulerPolicy(0, "graphics");
464  EXPECT_EQ(0, error);
465  error = dvrSetSchedulerPolicy(0, "graphics:low");
466  EXPECT_EQ(0, error);
467  error = dvrSetSchedulerPolicy(0, "graphics:high");
468  EXPECT_EQ(0, error);
469  error = dvrSetSchedulerPolicy(0, "sensors");
470  EXPECT_EQ(-EINVAL, error);
471  error = dvrSetSchedulerPolicy(0, "sensors:low");
472  EXPECT_EQ(-EINVAL, error);
473  error = dvrSetSchedulerPolicy(0, "sensors:high");
474  EXPECT_EQ(-EINVAL, error);
475  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
476  EXPECT_EQ(-EINVAL, error);
477  error = dvrSetSchedulerPolicy(0, "vr:app:render");
478  EXPECT_EQ(-EINVAL, error);
479
480  if (trusted_uid != -1) {
481    // uid=<trusted uid> / gid=AID_NOBODY
482    ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
483        << "Failed to restore uid: " << strerror(errno);
484    ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
485        << "Failed to restore gid: " << strerror(errno);
486    ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
487        << "Failed to set gid: " << strerror(errno);
488    ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1))
489        << "Failed to set uid: " << strerror(errno);
490
491    // Unprivileged policies.
492    error = dvrSetSchedulerPolicy(0, "batch");
493    EXPECT_EQ(0, error);
494    error = dvrSetSchedulerPolicy(0, "background");
495    EXPECT_EQ(0, error);
496    error = dvrSetSchedulerPolicy(0, "foreground");
497    EXPECT_EQ(0, error);
498    error = dvrSetSchedulerPolicy(0, "normal");
499    EXPECT_EQ(0, error);
500
501    // Privileged policies.
502    error = dvrSetSchedulerPolicy(0, "audio:low");
503    EXPECT_EQ(-EINVAL, error);
504    error = dvrSetSchedulerPolicy(0, "audio:high");
505    EXPECT_EQ(-EINVAL, error);
506    error = dvrSetSchedulerPolicy(0, "graphics");
507    EXPECT_EQ(-EINVAL, error);
508    error = dvrSetSchedulerPolicy(0, "graphics:low");
509    EXPECT_EQ(-EINVAL, error);
510    error = dvrSetSchedulerPolicy(0, "graphics:high");
511    EXPECT_EQ(-EINVAL, error);
512    error = dvrSetSchedulerPolicy(0, "sensors");
513    EXPECT_EQ(-EINVAL, error);
514    error = dvrSetSchedulerPolicy(0, "sensors:low");
515    EXPECT_EQ(-EINVAL, error);
516    error = dvrSetSchedulerPolicy(0, "sensors:high");
517    EXPECT_EQ(-EINVAL, error);
518    error = dvrSetSchedulerPolicy(0, "vr:system:arp");
519    EXPECT_EQ(0, error);
520    error = dvrSetSchedulerPolicy(0, "vr:app:render");
521    EXPECT_EQ(0, error);
522  }
523
524  // Restore original effective uid/gid.
525  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
526      << "Failed to restore gid: " << strerror(errno);
527  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
528      << "Failed to restore uid: " << strerror(errno);
529}
530