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