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/strings.h>
16 #include <android-base/unique_fd.h>
17 #include <dvr/performance_client_api.h>
18 #include <gtest/gtest.h>
19 #include <private/android_filesystem_config.h>
20
21 #include "stdio_filebuf.h"
22 #include "unique_file.h"
23
24 using android::base::Trim;
25 using android::dvr::UniqueFile;
26 using android::dvr::stdio_filebuf;
27
28 namespace {
29
30 const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
31
32 const char kProcBase[] = "/proc";
33
OpenTaskFile(pid_t task_id,const std::string & name)34 std::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
GetTaskCpuSet(pid_t task_id)44 std::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
TEST(PerformanceTest,SetCpuPartition)62 TEST(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
TEST(PerformanceTest,SetSchedulerClass)116 TEST(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
TEST(PerformanceTest,SetSchedulerPolicy)137 TEST(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
TEST(PerformanceTest,SchedulerClassResetOnFork)200 TEST(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
TEST(PerformanceTest,GetCpuPartition)219 TEST(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
TEST(PerformanceTest,Permissions)250 TEST(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