Merge "Trust navbar panel and accessibility overlays" into oc-dr1-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2f8840b..4161bd7 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -843,7 +843,7 @@
"-d", "*:v"});
}
-static void DumpIpTables() {
+static void DumpIpTablesAsRoot() {
RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
@@ -1013,6 +1013,24 @@
}
return;
}
+
+static void DumpPacketStats() {
+ DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+ DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+ DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+}
+
+static void DumpIpAddrAndRules() {
+ /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
+ RunCommand("NETWORK INTERFACES", {"ip", "link"});
+ RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+ RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
+ RunCommand("IP RULES", {"ip", "rule", "show"});
+ RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+}
+
static void dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
@@ -1090,23 +1108,11 @@
printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
}
- DumpFile("NETWORK DEV INFO", "/proc/net/dev");
- DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
- DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
- DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
- DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+ DumpPacketStats();
DoKmsg();
- /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
-
- RunCommand("NETWORK INTERFACES", {"ip", "link"});
-
- RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
- RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
-
- RunCommand("IP RULES", {"ip", "rule", "show"});
- RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+ DumpIpAddrAndRules();
dump_route_tables();
@@ -1215,6 +1221,46 @@
printf("========================================================\n");
}
+// This method collects dumpsys for telephony debugging only
+static void DumpstateTelephonyOnly() {
+ DurationReporter duration_reporter("DUMPSTATE");
+
+ DumpIpTablesAsRoot();
+
+ if (!DropRootUser()) {
+ return;
+ }
+
+ do_dmesg();
+ DoLogcat();
+ DumpPacketStats();
+ DoKmsg();
+ DumpIpAddrAndRules();
+ dump_route_tables();
+
+ RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+ CommandOptions::WithTimeout(10).Build());
+
+ RunCommand("SYSTEM PROPERTIES", {"getprop"});
+
+ printf("========================================================\n");
+ printf("== Android Framework Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
+ RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+
+ printf("========================================================\n");
+ printf("== Running Application Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
+
+ printf("========================================================\n");
+ printf("== dumpstate: done (id %d)\n", ds.id_);
+ printf("========================================================\n");
+}
+
void Dumpstate::DumpstateBoard() {
DurationReporter duration_reporter("dumpstate_board()");
printf("========================================================\n");
@@ -1752,13 +1798,7 @@
ds.PrintHeader();
if (telephony_only) {
- DumpIpTables();
- if (!DropRootUser()) {
- return -1;
- }
- do_dmesg();
- DoLogcat();
- DoKmsg();
+ DumpstateTelephonyOnly();
ds.DumpstateBoard();
} else {
// Dumps systrace right away, otherwise it will be filled with unnecessary events.
@@ -1793,7 +1833,7 @@
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
add_mountinfo();
- DumpIpTables();
+ DumpIpTablesAsRoot();
// Capture any IPSec policies in play. No keys are exposed here.
RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c2b10a9..3d36376 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -106,7 +106,7 @@
sp<FrameAvailableListener> listener;
{ // scope for the lock
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
@@ -121,7 +121,7 @@
sp<FrameAvailableListener> listener;
{
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
@@ -185,7 +185,7 @@
void ConsumerBase::setFrameAvailableListener(
const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
mFrameAvailableListener = listener;
}
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index d1a9b04..e9fc8fd 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -241,7 +241,9 @@
// mFrameAvailableListener is the listener object that will be called when a
// new frame becomes available. If it is not NULL it will be called from
- // queueBuffer.
+ // queueBuffer. The listener object is protected by mFrameAvailableMutex
+ // (not mMutex).
+ Mutex mFrameAvailableMutex;
wp<FrameAvailableListener> mFrameAvailableListener;
// The ConsumerBase has-a BufferQueue and is responsible for creating this object
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 4041d6b..7fe9825 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -31,6 +31,7 @@
"dvr_configuration_data.cpp",
"dvr_display_manager.cpp",
"dvr_hardware_composer_client.cpp",
+ "dvr_performance.cpp",
"dvr_surface.cpp",
"dvr_vsync.cpp",
]
@@ -45,6 +46,7 @@
"libvr_hwc-impl",
"libvr_hwc-binder",
"libgrallocusage",
+ "libperformance",
"libpdx_default_transport",
]
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index dc31917..7d4e2d1 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -10,6 +10,7 @@
#include <dvr/dvr_buffer_queue.h>
#include <dvr/dvr_configuration_data.h>
#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_performance.h>
#include <dvr/dvr_surface.h>
#include <dvr/dvr_vsync.h>
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
new file mode 100644
index 0000000..599101f
--- /dev/null
+++ b/libs/vr/libdvr/dvr_performance.cpp
@@ -0,0 +1,18 @@
+#include "include/dvr/dvr_performance.h"
+
+#include <private/dvr/performance_client.h>
+
+using android::dvr::PerformanceClient;
+
+extern "C" {
+
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
+} // extern "C"
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index c44f8a6..a3a47f1 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -2,6 +2,7 @@
#include <inttypes.h>
+#include <pdx/rpc/variant.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <private/dvr/display_client.h>
@@ -14,9 +15,20 @@
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttributeValue;
using android::dvr::CreateDvrReadBufferFromBufferConsumer;
+using android::pdx::rpc::EmptyVariant;
namespace {
+// Sets the Variant |destination| to the target std::array type and copies the C
+// array into it. Unsupported std::array configurations will fail to compile.
+template <typename T, std::size_t N>
+void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) {
+ using ArrayType = std::array<T, N>;
+ *destination = ArrayType{};
+ std::copy(std::begin(source), std::end(source),
+ std::get<ArrayType>(*destination).begin());
+}
+
bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes,
size_t attribute_count,
SurfaceAttributes* surface_attributes,
@@ -31,25 +43,31 @@
value = attributes[i].value.int64_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
- value = attributes[i].value.bool_value;
+ // bool_value is defined in an extern "C" block, which makes it look
+ // like an int to C++. Use a cast to assign the correct type to the
+ // Variant type SurfaceAttributeValue.
+ value = static_cast<bool>(attributes[i].value.bool_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT:
value = attributes[i].value.float_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2:
- value = attributes[i].value.float2_value;
+ ArrayCopy(&value, attributes[i].value.float2_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
- value = attributes[i].value.float3_value;
+ ArrayCopy(&value, attributes[i].value.float3_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
- value = attributes[i].value.float4_value;
+ ArrayCopy(&value, attributes[i].value.float4_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
- value = attributes[i].value.float8_value;
+ ArrayCopy(&value, attributes[i].value.float8_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
- value = attributes[i].value.float16_value;
+ ArrayCopy(&value, attributes[i].value.float16_value);
+ break;
+ case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
+ value = EmptyVariant{};
break;
default:
*error_index = i;
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 4b530b2..ca41e52 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <unistd.h>
#include <cstdio>
#include <dvr/dvr_display_types.h>
@@ -320,6 +321,10 @@
size_t layer_index,
size_t index);
+// dvr_performance.h
+typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
+ pid_t task_id, const char* scheduler_policy);
+
// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
// will populate. A DvrWriteBufferQueue must be created with this metadata iff
// ANativeWindow access is needed. Please do not remove, modify, or reorder
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 64e5e71..09bae84 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -151,3 +151,6 @@
// Read the native display metrics from the hardware composer
DVR_V1_API_ENTRY(GetNativeDisplayMetrics);
+
+// Performance
+DVR_V1_API_ENTRY(PerformanceSetSchedulerPolicy);
diff --git a/libs/vr/libdvr/include/dvr/dvr_performance.h b/libs/vr/libdvr/include/dvr/dvr_performance.h
new file mode 100644
index 0000000..5df35ad
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_performance.h
@@ -0,0 +1,26 @@
+#ifndef ANDROID_DVR_PERFORMANCE_H_
+#define ANDROID_DVR_PERFORMANCE_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+__END_DECLS
+
+#endif // ANDROID_DVR_PERFORMANCE_H_
+
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index 726949d..f83b26e 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -1,11 +1,13 @@
#include <android-base/properties.h>
#include <base/logging.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include <poll.h>
#include <android/hardware_buffer.h>
#include <algorithm>
+#include <array>
#include <set>
#include <thread>
#include <vector>
@@ -25,7 +27,30 @@
namespace {
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, bool value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
+ attribute.value.int32_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
+ attribute.value.int64_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
@@ -33,11 +58,56 @@
return attribute;
}
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
- attribute.value.bool_value = value;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
+ attribute.value.float_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 2>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
+ std::copy(value.begin(), value.end(), attribute.value.float2_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 3>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
+ std::copy(value.begin(), value.end(), attribute.value.float3_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 4>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
+ std::copy(value.begin(), value.end(), attribute.value.float4_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 8>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
+ std::copy(value.begin(), value.end(), attribute.value.float8_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 16>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
+ std::copy(value.begin(), value.end(), attribute.value.float16_value);
return attribute;
}
@@ -45,8 +115,8 @@
int32_t z_order = 0) {
DvrSurface* surface = nullptr;
DvrSurfaceAttribute attributes[] = {
- GetAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
- GetAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
const int ret = dvrSurfaceCreate(
attributes, std::extent<decltype(attributes)>::value, &surface);
@@ -101,13 +171,14 @@
return {};
}
- Status<void> WaitForUpdate() {
+ enum : int { kTimeoutMs = 10000 }; // 10s
+
+ Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
if (display_manager_event_fd_ < 0)
return ErrorStatus(-display_manager_event_fd_);
- const int kTimeoutMs = 10000; // 10s
pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
- const int count = poll(&pfd, 1, kTimeoutMs);
+ const int count = poll(&pfd, 1, timeout_ms);
if (count < 0)
return ErrorStatus(errno);
else if (count == 0)
@@ -471,20 +542,218 @@
auto attributes = attribute_status.take();
EXPECT_GE(attributes.size(), 2u);
- const std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- DVR_SURFACE_ATTRIBUTE_VISIBLE};
+ std::set<int32_t> actual_keys;
+ std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
// Collect all the keys in attributes that match the expected keys.
- std::set<int32_t> actual_keys;
- std::for_each(attributes.begin(), attributes.end(),
- [&expected_keys, &actual_keys](const auto& attribute) {
- if (expected_keys.find(attribute.key) != expected_keys.end())
- actual_keys.emplace(attribute.key);
- });
+ auto compare_keys = [](const auto& attributes, const auto& expected_keys) {
+ std::set<int32_t> keys;
+ for (const auto& attribute : attributes) {
+ if (expected_keys.find(attribute.key) != expected_keys.end())
+ keys.emplace(attribute.key);
+ }
+ return keys;
+ };
// If the sets match then attributes contained at least the expected keys,
// even if other keys were also present.
+ actual_keys = compare_keys(attributes, expected_keys);
EXPECT_EQ(expected_keys, actual_keys);
+
+ std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)};
+
+ // Test invalid args.
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(),
+ attributes_to_set.size()));
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr,
+ attributes_to_set.size()));
+
+ // Test attribute change events.
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+
+ // Verify the attributes changed flag is set.
+ auto check_flags = [](const auto& value) {
+ return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED;
+ };
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Test setting and then deleting an attribute.
+ const DvrSurfaceAttributeKey kUserKey = 1;
+ attributes_to_set = {MakeAttribute(kUserKey, 1024)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Delete the attribute.
+ attributes_to_set = {MakeAttribute(kUserKey, nullptr)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_NE(expected_keys, actual_keys);
+
+ // Test deleting a reserved attribute.
+ attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ // Failed attribute operations should not trigger update events.
+ const int kTimeoutMs = 100; // 0.1s
+ EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+}
+
+TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) {
+ // Create an application surface.
+ auto surface_status = CreateApplicationSurface();
+ ASSERT_STATUS_OK(surface_status);
+ UniqueDvrSurface surface = surface_status.take();
+ ASSERT_NE(nullptr, surface.get());
+
+ enum : std::int32_t {
+ kInt32Key = 1,
+ kInt64Key,
+ kBoolKey,
+ kFloatKey,
+ kFloat2Key,
+ kFloat3Key,
+ kFloat4Key,
+ kFloat8Key,
+ kFloat16Key,
+ };
+
+ const std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(kInt32Key, int32_t{0}),
+ MakeAttribute(kInt64Key, int64_t{0}),
+ MakeAttribute(kBoolKey, false),
+ MakeAttribute(kFloatKey, 0.0f),
+ MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}),
+ MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}),
+ MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}),
+ MakeAttribute(kFloat8Key,
+ std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+ 15.0f, 16.0f, 17.0f}}),
+ MakeAttribute(kFloat16Key, std::array<float, 16>{
+ {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f,
+ 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f,
+ 30.0f, 31.0f, 32.0f, 33.0f}})};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ auto attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ auto attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), attributes_to_set.size());
+
+ auto HasAttribute = [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> bool {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return true;
+ }
+ return false;
+ };
+ auto AttributeType =
+ [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return attribute.value.type;
+ }
+ return DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ };
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt32Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+ AttributeType(attributes, kInt32Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt64Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64,
+ AttributeType(attributes, kInt64Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kBoolKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+ AttributeType(attributes, kBoolKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloatKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT,
+ AttributeType(attributes, kFloatKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat2Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2,
+ AttributeType(attributes, kFloat2Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat3Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3,
+ AttributeType(attributes, kFloat3Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat4Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4,
+ AttributeType(attributes, kFloat4Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat8Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8,
+ AttributeType(attributes, kFloat8Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat16Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16,
+ AttributeType(attributes, kFloat16Key));
}
TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
@@ -500,7 +769,8 @@
ASSERT_STATUS_OK(manager_->WaitForUpdate());
ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
- // Verify there are no queues for the surface recorded in the state snapshot.
+ // Verify there are no queues for the surface recorded in the state
+ // snapshot.
EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
// Create a new queue in the surface.
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index dc321fa..80b1769 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -26,14 +26,35 @@
template <std::size_t I, typename... Types>
using TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>;
+// Similar to std::is_constructible except that it evaluates to false for bool
+// construction from pointer types: this helps prevent subtle to bugs caused by
+// assigning values that decay to pointers to Variants with bool elements.
+//
+// Here is an example of the problematic situation this trait avoids:
+//
+// Variant<int, bool> v;
+// const int array[3] = {1, 2, 3};
+// v = array; // This is allowed by regular std::is_constructible.
+//
+template <typename...>
+struct IsConstructible;
+template <typename T, typename U>
+struct IsConstructible<T, U>
+ : std::integral_constant<bool,
+ std::is_constructible<T, U>::value &&
+ !(std::is_same<std::decay_t<T>, bool>::value &&
+ std::is_pointer<std::decay_t<U>>::value)> {};
+template <typename T, typename... Args>
+struct IsConstructible<T, Args...> : std::is_constructible<T, Args...> {};
+
// Enable if T(Args...) is well formed.
template <typename R, typename T, typename... Args>
using EnableIfConstructible =
- typename std::enable_if<std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<IsConstructible<T, Args...>::value, R>::type;
// Enable if T(Args...) is not well formed.
template <typename R, typename T, typename... Args>
using EnableIfNotConstructible =
- typename std::enable_if<!std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<!IsConstructible<T, Args...>::value, R>::type;
// Determines whether T is an element of Types...;
template <typename... Types>
@@ -65,12 +86,11 @@
struct ConstructibleCount;
template <typename From, typename To>
struct ConstructibleCount<From, To>
- : std::integral_constant<std::size_t,
- std::is_constructible<To, From>::value> {};
+ : std::integral_constant<std::size_t, IsConstructible<To, From>::value> {};
template <typename From, typename First, typename... Rest>
struct ConstructibleCount<From, First, Rest...>
: std::integral_constant<std::size_t,
- std::is_constructible<First, From>::value +
+ IsConstructible<First, From>::value +
ConstructibleCount<From, Rest...>::value> {};
// Enable if T is an element of Types...
@@ -126,6 +146,18 @@
: first_(std::forward<T>(value)) {
*index_out = index;
}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(other.first_);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(std::move(other.first_));
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
Type& get(TypeTag<Type>) { return first_; }
const Type& get(TypeTag<Type>) const { return first_; }
@@ -217,6 +249,22 @@
template <typename T, typename U>
Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value)
: rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(other.first_);
+ else
+ new (&rest_) Union<Rest...>(other.rest_, index - 1);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(std::move(other.first_));
+ else
+ new (&rest_) Union<Rest...>(std::move(other.rest_), index - 1);
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
struct FirstType {};
struct RestType {};
@@ -351,6 +399,10 @@
} // namespace detail
+// Variant is a type safe union that can store values of any of its element
+// types. A Variant is different than std::tuple in that it only stores one type
+// at a time or a special empty type. Variants are always default constructible
+// to empty, even when none of the element types are default constructible.
template <typename... Types>
class Variant {
private:
@@ -393,6 +445,11 @@
explicit Variant(EmptyVariant) {}
~Variant() { Destruct(); }
+ Variant(const Variant& other)
+ : index_{other.index_}, value_{other.value_, other.index_} {}
+ Variant(Variant&& other)
+ : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
+
// Copy and move construction from Variant types. Each element of OtherTypes
// must be convertible to an element of Types.
template <typename... OtherTypes>
@@ -404,6 +461,15 @@
other.Visit([this](auto&& value) { Construct(std::move(value)); });
}
+ Variant& operator=(const Variant& other) {
+ other.Visit([this](const auto& value) { *this = value; });
+ return *this;
+ }
+ Variant& operator=(Variant&& other) {
+ other.Visit([this](auto&& value) { *this = std::move(value); });
+ return *this;
+ }
+
// Construction from non-Variant types.
template <typename T, typename = EnableIfAssignable<void, T>>
explicit Variant(T&& value)
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index b1ebc9b..e3520f5 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -1,3 +1,4 @@
+#include <array>
#include <cstdint>
#include <functional>
#include <memory>
@@ -1097,6 +1098,29 @@
EXPECT_FALSE((detail::HasType<char&, int, float, bool>::value));
}
+TEST(Variant, IsConstructible) {
+ using ArrayType = const float[3];
+ struct ImplicitBool {
+ operator bool() const { return true; }
+ };
+ struct ExplicitBool {
+ explicit operator bool() const { return true; }
+ };
+ struct NonBool {};
+ struct TwoArgs {
+ TwoArgs(int, bool) {}
+ };
+
+ EXPECT_FALSE((detail::IsConstructible<bool, ArrayType>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, int>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ImplicitBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ExplicitBool>::value));
+ EXPECT_FALSE((detail::IsConstructible<bool, NonBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<TwoArgs, int, bool>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int, std::string>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int>::value));
+}
+
TEST(Variant, Set) {
EXPECT_TRUE((detail::Set<int, bool, float>::template IsSubset<int, bool,
float>::value));
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index ac4dea9..ebe7cea 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -100,6 +100,9 @@
ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
status.GetErrorMessage().c_str());
return status;
+ } else if (count == 0) {
+ status.SetError(ETIMEDOUT);
+ return status;
}
const int mask_out = event.data.u32;
diff --git a/libs/vr/libperformance/include/dvr/performance_client_api.h b/libs/vr/libperformance/include/dvr/performance_client_api.h
index 2216e38..9d617cb 100644
--- a/libs/vr/libperformance/include/dvr/performance_client_api.h
+++ b/libs/vr/libperformance/include/dvr/performance_client_api.h
@@ -8,6 +8,20 @@
extern "C" {
#endif
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
/// Sets the CPU partition for a task.
///
/// Sets the CPU partition for a task to the partition described by a CPU
diff --git a/libs/vr/libperformance/include/private/dvr/performance_client.h b/libs/vr/libperformance/include/private/dvr/performance_client.h
index a61c6b2..3bd90dc 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_client.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_client.h
@@ -14,6 +14,10 @@
class PerformanceClient : public pdx::ClientBase<PerformanceClient> {
public:
+ int SetSchedulerPolicy(pid_t task_id, const std::string& scheduler_policy);
+ int SetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+ // TODO(eieio): Consider deprecating this API.
int SetCpuPartition(pid_t task_id, const std::string& partition);
int SetCpuPartition(pid_t task_id, const char* partition);
int SetSchedulerClass(pid_t task_id, const std::string& scheduler_class);
diff --git a/libs/vr/libperformance/include/private/dvr/performance_rpc.h b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
index 73bdaa7..d57bbe8 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_rpc.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
@@ -21,14 +21,17 @@
kOpSetCpuPartition = 0,
kOpSetSchedulerClass,
kOpGetCpuPartition,
+ kOpSetSchedulerPolicy,
};
// Methods.
PDX_REMOTE_METHOD(SetCpuPartition, kOpSetCpuPartition,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(SetSchedulerClass, kOpSetSchedulerClass,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(GetCpuPartition, kOpGetCpuPartition, std::string(pid_t));
+ PDX_REMOTE_METHOD(SetSchedulerPolicy, kOpSetSchedulerPolicy,
+ void(pid_t, const std::string&));
};
} // namespace dvr
diff --git a/libs/vr/libperformance/performance_client.cpp b/libs/vr/libperformance/performance_client.cpp
index 2124162..bf3726e 100644
--- a/libs/vr/libperformance/performance_client.cpp
+++ b/libs/vr/libperformance/performance_client.cpp
@@ -37,6 +37,26 @@
task_id, WrapString(partition)));
}
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const std::string& scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(task_id,
+ scheduler_policy));
+}
+
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ task_id, WrapString(scheduler_policy)));
+}
+
int PerformanceClient::SetSchedulerClass(pid_t task_id,
const std::string& scheduler_class) {
if (task_id == 0)
@@ -101,6 +121,15 @@
return error;
}
+extern "C" int dvrSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = android::dvr::PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
extern "C" int dvrSetSchedulerClass(pid_t task_id,
const char* scheduler_class) {
int error;
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 330b455..6e18781 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -68,7 +68,7 @@
display::SurfaceUpdateFlags update_flags;
for (const auto& attribute : attributes) {
- const auto& key = attribute.first;
+ const auto key = attribute.first;
const auto* variant = &attribute.second;
bool invalid_value = false;
bool visibility_changed = false;
@@ -95,14 +95,23 @@
break;
}
+ // Only update the attribute map with valid values. This check also has the
+ // effect of preventing special attributes handled above from being deleted
+ // by an empty value.
if (invalid_value) {
ALOGW(
"DisplaySurface::OnClientSetAttributes: Failed to set display "
"surface attribute '%d' because of incompatible type: %d",
key, variant->index());
} else {
- // Only update the attribute map with valid values.
- attributes_[attribute.first] = attribute.second;
+ // An empty value indicates the attribute should be deleted.
+ if (variant->empty()) {
+ auto search = attributes_.find(key);
+ if (search != attributes_.end())
+ attributes_.erase(search);
+ } else {
+ attributes_[key] = *variant;
+ }
// All attribute changes generate a notification, even if the value
// doesn't change. Visibility attributes set a flag only if the value
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..f41da87 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -32,6 +32,9 @@
// Called on a binder thread.
void OnHardwareComposerRefresh();
+ // dump all vr flinger state.
+ std::string Dump();
+
private:
VrFlinger();
bool Init(Hwc2::Composer* hidl,
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b2dc1d8..3a0ca4a 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -139,6 +139,11 @@
display_service_->OnHardwareComposerRefresh();
}
+std::string VrFlinger::Dump() {
+ // TODO(karthikrs): Add more state information here.
+ return display_service_->DumpState(0/*unused*/);
+}
+
void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
bool enabled) {
ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
@@ -146,6 +151,5 @@
// Persistent VR mode is not enough.
// request_display_callback_(enabled);
}
-
} // namespace dvr
} // namespace android
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 25a3dc5..cf5ab05 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -24,7 +24,6 @@
#include <sched.h>
-#include <thread>
#include "EventQueue.h"
#include "DirectReportChannel.h"
@@ -40,20 +39,24 @@
using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
using ::android::hardware::hidl_vec;
using ::android::hardware::Void;
-using ::android::sp;
static const char* POLL_THREAD_NAME = "hidl_ssvc_poll";
SensorManager::SensorManager(JavaVM* vm)
- : mJavaVm(vm) {
+ : mLooper(new Looper(false /*allowNonCallbacks*/)), mStopThread(true), mJavaVm(vm) {
}
SensorManager::~SensorManager() {
// Stops pollAll inside the thread.
- std::unique_lock<std::mutex> lock(mLooperMutex);
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ mStopThread = true;
if (mLooper != nullptr) {
mLooper->wake();
}
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
}
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -128,12 +131,13 @@
}
/* One global looper for all event queues created from this SensorManager. */
-sp<::android::Looper> SensorManager::getLooper() {
- std::unique_lock<std::mutex> lock(mLooperMutex);
- if (mLooper == nullptr) {
- std::condition_variable looperSet;
+sp<Looper> SensorManager::getLooper() {
+ std::lock_guard<std::mutex> lock(mThreadMutex);
- std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet, javaVm = mJavaVm] {
+ if (!mPollThread.joinable()) {
+ // if thread not initialized, start thread
+ mStopThread = false;
+ std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
struct sched_param p = {0};
p.sched_priority = 10;
@@ -142,16 +146,11 @@
<< strerror(errno);
}
- std::unique_lock<std::mutex> lock(mutex);
- if (looper != nullptr) {
- LOG(INFO) << "Another thread has already set the looper, exiting this one.";
- return;
- }
- looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
- lock.unlock();
+ // set looper
+ Looper::setForThread(looper);
- // Attach the thread to JavaVM so that pollAll do not crash if the event
- // is from Java.
+ // Attach the thread to JavaVM so that pollAll do not crash if the thread
+ // eventually calls into Java.
JavaVMAttachArgs args{
.version = JNI_VERSION_1_2,
.name = POLL_THREAD_NAME,
@@ -162,19 +161,30 @@
LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
}
- looperSet.notify_one();
- int pollResult = looper->pollAll(-1 /* timeout */);
- if (pollResult != ALOOPER_POLL_WAKE) {
- LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+ LOG(INFO) << POLL_THREAD_NAME << " started.";
+ for (;;) {
+ int pollResult = looper->pollAll(-1 /* timeout */);
+ if (pollResult == Looper::POLL_WAKE) {
+ if (stopThread == true) {
+ LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+ break;
+ } else {
+ LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+ }
+ } else {
+ LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+ << pollResult;
+ break;
+ }
}
if (javaVm->DetachCurrentThread() != JNI_OK) {
LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
}
- LOG(INFO) << "Looper thread is terminated.";
- }}.detach();
- looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
+ LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+ }};
+ mPollThread = std::move(pollThread);
}
return mLooper;
}
@@ -196,6 +206,12 @@
}
sp<::android::Looper> looper = getLooper();
+ if (looper == nullptr) {
+ LOG(ERROR) << "::android::SensorManager::createEventQueue cannot initialize looper";
+ _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+ return Void();
+ }
+
sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue();
if (internalQueue == nullptr) {
LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index e66c8e5..ddcee28 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -20,6 +20,7 @@
#include <jni.h>
#include <mutex>
+#include <thread>
#include <android/frameworks/sensorservice/1.0/ISensorManager.h>
#include <android/frameworks/sensorservice/1.0/types.h>
@@ -38,6 +39,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_memory;
using ::android::hardware::Return;
+using ::android::sp;
struct SensorManager final : public ISensorManager {
@@ -54,13 +56,15 @@
private:
// Block until ::android::SensorManager is initialized.
::android::SensorManager& getInternalManager();
- sp<::android::Looper> getLooper();
+ sp<Looper> getLooper();
std::mutex mInternalManagerMutex;
::android::SensorManager* mInternalManager = nullptr; // does not own
+ sp<Looper> mLooper;
- std::mutex mLooperMutex;
- sp<::android::Looper> mLooper;
+ volatile bool mStopThread;
+ std::mutex mThreadMutex; //protects mPollThread
+ std::thread mPollThread;
JavaVM* mJavaVm;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5aed896..273f194 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1952,7 +1952,6 @@
mCurrentState.barrierLayer = nullptr;
mCurrentState.frameNumber = 0;
mCurrentState.modified = false;
- ALOGE("Deferred transaction");
}
void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8192968..d128a06 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3770,6 +3770,15 @@
*/
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
+
+ /*
+ * Dump VrFlinger state if in use.
+ */
+ if (mVrFlingerRequestsDisplay && mVrFlinger) {
+ result.append("VrFlinger state:\n");
+ result.append(mVrFlinger->Dump().c_str());
+ result.append("\n");
+ }
}
const Vector< sp<Layer> >&
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 9babeef..abc8fde 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -240,10 +240,15 @@
}
void SurfaceFlingerConsumer::onSidebandStreamChanged() {
+ FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+ {
+ Mutex::Autolock lock(mFrameAvailableMutex);
+ unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
+ }
sp<ContentsChangedListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
- ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+ ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
listener = mContentsChangedListener.promote();
}
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 6256e90..dbc66f1 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -23,8 +23,10 @@
staticLibraries := \
libperformance \
libpdx_default_transport \
+ libvr_manager
sharedLibraries := \
+ libbinder \
libbase \
libcutils \
liblog \
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a3723f..1a7264c 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -15,6 +15,9 @@
#include "task.h"
#include "unique_file.h"
+using android::pdx::ErrorStatus;
+using android::pdx::Status;
+
namespace {
constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
@@ -176,11 +179,11 @@
task_id, task.name().c_str(), target_set.c_str(),
task.thread_group_id(), task.parent_process_id());
- const int ret = target->AttachTask(task_id);
- ALOGW_IF(ret < 0 && ret != -EINVAL,
+ auto status = target->AttachTask(task_id);
+ ALOGW_IF(!status && status.error() != EINVAL,
"CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d "
"to cpuset=%s: %s",
- task_id, target_set.c_str(), strerror(-ret));
+ task_id, target_set.c_str(), status.GetErrorMessage().c_str());
} else {
ALOGD_IF(TRACE,
"CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.",
@@ -233,7 +236,7 @@
return fp;
}
-int CpuSet::AttachTask(pid_t task_id) const {
+Status<void> CpuSet::AttachTask(pid_t task_id) const {
auto file = OpenFile("tasks", O_RDWR);
if (file.get() >= 0) {
std::ostringstream stream;
@@ -241,11 +244,15 @@
std::string value = stream.str();
const bool ret = base::WriteStringToFd(value, file.get());
- return !ret ? -errno : 0;
+ if (!ret)
+ return ErrorStatus(errno);
+ else
+ return {};
} else {
+ const int error = errno;
ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(),
- strerror(errno));
- return -errno;
+ strerror(error));
+ return ErrorStatus(error);
}
}
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index fcf280a..6879272 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -11,6 +11,8 @@
#include <android-base/unique_fd.h>
+#include <pdx/status.h>
+
#include "unique_file.h"
namespace android {
@@ -28,7 +30,7 @@
std::string GetCpuList() const;
- int AttachTask(pid_t task_id) const;
+ pdx::Status<void> AttachTask(pid_t task_id) const;
std::vector<pid_t> GetTasks() const;
private:
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 955c661..3f7009a 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -8,14 +8,20 @@
#include <pdx/rpc/argument_encoder.h>
#include <pdx/rpc/message_buffer.h>
#include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/performance_rpc.h>
+#include <private/dvr/trusted_uids.h>
#include "task.h"
// This prctl is only available in Android kernels.
#define PR_SET_TIMERSLACK_PID 41
+using android::dvr::IsTrustedUid;
+using android::dvr::Task;
+using android::pdx::ErrorStatus;
using android::pdx::Message;
+using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
@@ -26,6 +32,68 @@
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
+// Expands the given parameter pack expression using an initializer list to
+// guarantee ordering and a comma expression to guarantee even void expressions
+// are valid elements of the initializer list.
+#define EXPAND_PACK(...) \
+ std::initializer_list<int> { (__VA_ARGS__, 0)... }
+
+// Returns true if the sender's euid matches any of the uids in |UIDs|.
+template <uid_t... UIDs>
+struct UserId {
+ static bool Check(const Message& sender, const Task&) {
+ const uid_t uid = sender.GetEffectiveUserId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (uid == UIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's egid matches any of the gids in |GIDs|.
+template <gid_t... GIDs>
+struct GroupId {
+ static bool Check(const Message& sender, const Task&) {
+ const gid_t gid = sender.GetEffectiveGroupId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (gid == GIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's euid is trusted according to VR manager service.
+struct Trusted {
+ static bool Check(const Message& sender, const Task&) {
+ return IsTrustedUid(sender.GetEffectiveUserId(), false);
+ }
+};
+
+// Returns returns true if the task belongs to the sending process.
+struct SameProcess {
+ static bool Check(const Message& sender, const Task& task) {
+ return sender.GetProcessId() == task.thread_group_id();
+ }
+};
+
+// Returns true if any of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckOr {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = false;
+ EXPAND_PACK(allow |= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
+// Returns true if all of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckAnd {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = true;
+ EXPAND_PACK(allow &= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
} // anonymous namespace
namespace android {
@@ -48,43 +116,79 @@
const int fifo_low = sched_fifo_min_priority_;
const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5;
- // TODO(eieio): Make this configurable on the command line.
+ // TODO(eieio): Make this configurable on the command line or config file.
cpuset_.MoveUnboundTasks("/kernel");
+ // TODO(eieio): Replace this witha device-specific config file. This is just a
+ // hack for now to put some form of permission logic in place while a longer
+ // term solution is developed.
+ using AllowRootSystem =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>,
+ GroupId<AID_SYSTEM>>>;
+ using AllowRootSystemGraphics =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
+ GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
+ using AllowRootSystemAudio =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
+ GroupId<AID_SYSTEM, AID_AUDIO>>>;
+ using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>,
+ GroupId<AID_SYSTEM>>;
+
+ partition_permission_check_ = AllowRootSystemTrusted::Check;
+
// Setup the scheduler classes.
+ // TODO(eieio): Replace this with a device-specific config file.
scheduler_classes_ = {
{"audio:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemAudio::Check}},
{"audio:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 3}},
+ .priority = fifo_medium + 3,
+ .permission_check = AllowRootSystemAudio::Check}},
{"graphics",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 2}},
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"sensors",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low + 1}},
+ .priority = fifo_low + 1,
+ .permission_check = AllowRootSystem::Check}},
+ {"vr:system:arp",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemTrusted::Check}},
+ {"vr:app:render",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 1,
+ .permission_check = AllowRootSystemTrusted::Check}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_NORMAL,
@@ -113,67 +217,94 @@
return cpuset_.DumpState();
}
-int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id,
- const std::string& partition) {
+Status<void> PerformanceService::OnSetSchedulerPolicy(
+ Message& message, pid_t task_id, const std::string& scheduler_policy) {
+ // Forward to scheduler class handler for now. In the future this method will
+ // subsume the others by unifying both scheduler class and cpu partiton into a
+ // single policy concept.
+ ALOGI(
+ "PerformanceService::OnSetSchedulerPolicy: task_id=%d "
+ "scheduler_policy=%s",
+ task_id, scheduler_policy.c_str());
+ return OnSetSchedulerClass(message, task_id, scheduler_policy);
+}
+
+Status<void> PerformanceService::OnSetCpuPartition(
+ Message& message, pid_t task_id, const std::string& partition) {
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ return ErrorStatus(EINVAL);
+
+ // Temporary permission check.
+ // TODO(eieio): Replace this with a configuration file.
+ if (partition_permission_check_ &&
+ !partition_permission_check_(message, task)) {
+ return ErrorStatus(EINVAL);
+ }
auto target_set = cpuset_.Lookup(partition);
if (!target_set)
- return -ENOENT;
+ return ErrorStatus(ENOENT);
- const auto attach_error = target_set->AttachTask(task_id);
- if (attach_error)
- return attach_error;
+ auto attach_status = target_set->AttachTask(task_id);
+ if (!attach_status)
+ return attach_status;
- return 0;
+ return {};
}
-int PerformanceService::OnSetSchedulerClass(
+Status<void> PerformanceService::OnSetSchedulerClass(
Message& message, pid_t task_id, const std::string& scheduler_class) {
- // Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ if (!task)
+ return ErrorStatus(EINVAL);
- struct sched_param param;
-
- // TODO(eieio): Apply rules based on the requesting process. Applications are
- // only allowed one audio thread that runs at SCHED_FIFO. System services can
- // have more than one.
auto search = scheduler_classes_.find(scheduler_class);
if (search != scheduler_classes_.end()) {
auto config = search->second;
+
+ // Make sure the sending process is allowed to make the requested change to
+ // this task.
+ if (!config.IsAllowed(message, task))
+ return ErrorStatus(EINVAL);
+
+ struct sched_param param;
param.sched_priority = config.priority;
+
sched_setscheduler(task_id, config.scheduler_policy, ¶m);
prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.",
task_id, scheduler_class.c_str());
- return 0;
+ return {};
} else {
ALOGE(
"PerformanceService::OnSetSchedulerClass: Invalid class=%s requested "
"by task=%d.",
scheduler_class.c_str(), task_id);
- return -EINVAL;
+ return ErrorStatus(EINVAL);
}
}
-std::string PerformanceService::OnGetCpuPartition(Message& message,
- pid_t task_id) {
+Status<std::string> PerformanceService::OnGetCpuPartition(Message& message,
+ pid_t task_id) {
// Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- REPLY_ERROR_RETURN(message, EINVAL, "");
+ return ErrorStatus(EINVAL);
return task.GetCpuSetPath();
}
-pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
+Status<void> PerformanceService::HandleMessage(Message& message) {
+ ALOGD_IF(TRACE, "PerformanceService::HandleMessage: op=%d", message.GetOp());
switch (message.GetOp()) {
+ case PerformanceRPC::SetSchedulerPolicy::Opcode:
+ DispatchRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ *this, &PerformanceService::OnSetSchedulerPolicy, message);
+ return {};
+
case PerformanceRPC::SetCpuPartition::Opcode:
- DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
+ DispatchRemoteMethod<PerformanceRPC::SetCpuPartition>(
*this, &PerformanceService::OnSetCpuPartition, message);
return {};
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 34abba7..b812535 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -1,12 +1,14 @@
#ifndef ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
#define ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
+#include <functional>
#include <string>
#include <unordered_map>
#include <pdx/service.h>
#include "cpu_set.h"
+#include "task.h"
namespace android {
namespace dvr {
@@ -27,11 +29,15 @@
PerformanceService();
- int OnSetCpuPartition(pdx::Message& message, pid_t task_id,
- const std::string& partition);
- int OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
- const std::string& scheduler_class);
- std::string OnGetCpuPartition(pdx::Message& message, pid_t task_id);
+ pdx::Status<void> OnSetSchedulerPolicy(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+
+ pdx::Status<void> OnSetCpuPartition(pdx::Message& message, pid_t task_id,
+ const std::string& partition);
+ pdx::Status<void> OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+ pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
+ pid_t task_id);
CpuSetManager cpuset_;
@@ -43,10 +49,24 @@
unsigned long timer_slack;
int scheduler_policy;
int priority;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ permission_check;
+
+ // Check the permisison of the given task to use this scheduler class. If a
+ // permission check function is not set then all tasks are allowed.
+ bool IsAllowed(const pdx::Message& message, const Task& task) const {
+ if (permission_check)
+ return permission_check(message, task);
+ else
+ return true;
+ }
};
std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ partition_permission_check_;
+
PerformanceService(const PerformanceService&) = delete;
void operator=(const PerformanceService&) = delete;
};
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index b526082..7de1f08 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,12 +1,22 @@
#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;
@@ -86,6 +96,27 @@
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;
@@ -135,3 +166,273 @@
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!";
+
+ // 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);
+}