* @brief A crippled abstraction of widely praised, but often misused communication mechanism
*/
+#include <poll.h>
#include <stdexcept>
#include <unistd.h>
}
void SynchronizationPipe::post() {
+ post("#", 1);
+}
+
+void SynchronizationPipe::wait() {
+ char dummy;
+ wait(&dummy, 1);
+}
+
+void SynchronizationPipe::pollForWait() {
RUNNER_ASSERT_MSG(m_epClaimed == true, "Endpoint not claimed");
- auto ret = TEMP_FAILURE_RETRY(write(m_writeEp, "#", 1));
+
+ pollfd fds[1];
+ fds->fd = m_readEp;
+ fds->events = POLLIN;
+ auto ret = TEMP_FAILURE_RETRY(poll(fds, 1, -1));
+ RUNNER_ASSERT_ERRNO(ret > 0);
+}
+
+void SynchronizationPipe::post(const void *data, size_t size) {
+ RUNNER_ASSERT_MSG(m_epClaimed == true, "Endpoint not claimed");
+ auto ret = TEMP_FAILURE_RETRY(write(m_writeEp, data, size));
RUNNER_ASSERT_ERRNO_MSG(ret > 0, "Write failed ret = " << ret);
}
-void SynchronizationPipe::wait() {
+void SynchronizationPipe::wait(void *data, size_t size) {
RUNNER_ASSERT_MSG(m_epClaimed == true, "Endpoint not claimed");
- char buf;
- auto ret = TEMP_FAILURE_RETRY(read(m_readEp, &buf, 1));
+ auto ret = TEMP_FAILURE_RETRY(read(m_readEp, data, size));
RUNNER_ASSERT_ERRNO_MSG(ret > 0, "Read failed ret = " << ret);
}
Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
}
}
+
+namespace {
+class Timestamp {
+ uint64_t _;
+ explicit Timestamp(uint64_t ts) : _(ts) {}
+public:
+ Timestamp operator-(const Timestamp &other) const {
+ RUNNER_ASSERT(_ > other._);
+ return Timestamp(_ - other._);
+ }
+ Timestamp operator+(const Timestamp &other) const {
+ return Timestamp(_ + other._);
+ }
+ bool operator<(const Timestamp &other) const {
+ return _ < other._;
+ }
+ Timestamp() = default;
+ static Timestamp now() {
+ timespec ts;
+ const auto res = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ RUNNER_ASSERT_ERRNO(!res);
+ return Timestamp(ts.tv_sec * 1000000000ULL + ts.tv_nsec);
+ }
+ static void report(const Timestamp *ts, size_t n) {
+ //TODO calc/feedback
+ for (size_t i = 0; i < n; i++)
+ std::cerr << i << ": " << ts[i]._ << '\n';
+ }
+};
+} // namespace
+
+RUNNER_TEST(security_manager_200_prepare_app_perf)
+{
+ TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
+ tmpUser.create();
+
+ constexpr int nApps = 2; // 2+ == intermittent fail TODO investigate
+
+ std::vector<AppInstallHelper> apps;
+ const auto uid = tmpUser.getUid();
+ std::vector<ScopedInstaller> appInstalls;
+ apps.reserve(nApps);
+ appInstalls.reserve(nApps);
+
+ for (int i = 0; i < nApps; i++) {
+ apps.emplace_back(AppInstallHelper("app200_" + std::to_string(i), uid));
+ auto &app = apps.back();
+ for (const auto &p : { EXTERNAL_STORAGE_PRIVILEGE, MEDIA_STORAGE_PRIVILEGE })
+ app.addPrivilege(p);
+ appInstalls.emplace_back(ScopedInstaller(app));
+ }
+
+ SynchronizationPipe synchPipe;
+ for (const auto &app : apps) {
+ pid_t pid = fork();
+ RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
+ if (!pid) {
+ synchPipe.claimChildEp();
+ RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
+
+ const auto appId = app.getAppId();
+
+ synchPipe.post(); // declare readiness to start measuring
+ synchPipe.pollForWait(); // wait for parent to signal all children simultaneously
+
+ Timestamp beg = Timestamp::now();
+ Api::prepareAppCandidate();
+ Timestamp mid = Timestamp::now();
+ Api::prepareApp(appId);
+ Timestamp end = Timestamp::now();
+
+ Timestamp ts[2] = { mid-beg, end-mid };
+ synchPipe.post(ts, sizeof ts); // post measurement payload
+ exit(0);
+ }
+ }
+
+ synchPipe.claimParentEp();
+ for (int i = 0; i < nApps; i++) // wait for all kids to be ready to start measurement
+ synchPipe.wait();
+ synchPipe.post(); // signal them all simultaneously
+
+ Timestamp candidate[nApps], prepare[nApps], everything[nApps];
+ for (int i = 0; i < nApps; i++) {
+ Timestamp ts[2];
+ synchPipe.wait(ts, sizeof ts);
+ candidate[i] = ts[0];
+ prepare[i] = ts[1];
+ everything[i] = ts[0] + ts[1];
+ Api::cleanupApp(apps[i].getAppId(), uid, waitPid());
+ }
+ Timestamp::report(candidate, nApps);
+ Timestamp::report(prepare, nApps);
+ Timestamp::report(everything, nApps);
+}