Merge "Add dumpsys finish timestamp" into oc-mr1-dev
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 2b2725f..9ab56dd 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1137,10 +1137,9 @@
// (re)Creates the app image if needed.
Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
bool is_public, int uid, bool is_secondary_dex) {
- // Use app images only if it is enabled (by a set image format) and we are compiling
- // profile-guided (so the app image doesn't conservatively contain all classes).
- // Note that we don't create an image for secondary dex files.
- if (is_secondary_dex || !profile_guided) {
+
+ // We don't create an image for secondary dex files.
+ if (is_secondary_dex) {
return Dex2oatFileWrapper();
}
@@ -1149,6 +1148,14 @@
// Happens when the out_oat_path has an unknown extension.
return Dex2oatFileWrapper();
}
+
+ // Use app images only if it is enabled (by a set image format) and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ if (!profile_guided) {
+ // In case there is a stale image, remove it now. Ignore any error.
+ unlink(image_path.c_str());
+ return Dex2oatFileWrapper();
+ }
char app_image_format[kPropertyValueMax];
bool have_app_image_format =
get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
index 38980f3..85ac78f 100644
--- a/include/android/sharedmem_jni.h
+++ b/include/android/sharedmem_jni.h
@@ -67,7 +67,8 @@
* \param env The JNIEnv* pointer
* \param sharedMemory The Java android.os.SharedMemory object
* \return file descriptor that denotes the shared memory; -1 if the shared memory object is
- * already closed or if the JNIEnv or jobject is NULL.
+ * already closed, if the JNIEnv or jobject is NULL, or if there are too many open file
+ * descriptors (errno=EMFILE)
*/
int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory);
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index 39adc5e..755e60c 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -76,7 +76,7 @@
mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]);
mMinLuminance = reinterpret_cast<float const&>(buf[2]);
if (itemCount) {
- mSupportedHdrTypes.reserve(itemCount);
+ mSupportedHdrTypes.resize(itemCount);
for (size_t i = 0; i < itemCount; ++i) {
mSupportedHdrTypes[i] = buf[4 + i];
}
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 018abbb..e4e20f9 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -14,6 +14,8 @@
using android::dvr::BufferProducer;
using android::dvr::ConsumerQueue;
using android::dvr::ProducerQueue;
+using android::dvr::ProducerQueueConfigBuilder;
+using android::dvr::UsagePolicy;
extern "C" {
@@ -156,6 +158,36 @@
return 0;
}
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t layer_count, uint64_t usage,
+ size_t capacity, size_t metadata_size,
+ DvrWriteBufferQueue** out_write_queue) {
+ if (!out_write_queue)
+ return -EINVAL;
+
+ auto config_builder = ProducerQueueConfigBuilder()
+ .SetDefaultWidth(width)
+ .SetDefaultHeight(height)
+ .SetDefaultFormat(format)
+ .SetMetadataSize(metadata_size);
+ std::unique_ptr<ProducerQueue> producer_queue =
+ ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
+ if (!producer_queue) {
+ ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
+ return -ENOMEM;
+ }
+
+ auto status = producer_queue->AllocateBuffers(width, height, layer_count,
+ format, usage, capacity);
+ if (!status.ok()) {
+ ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
+ return -ENOMEM;
+ }
+
+ *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
+ return 0;
+}
+
void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
delete write_queue;
}
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index d0dbd8d..451d037 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -159,6 +159,12 @@
DvrBuffer* buffer);
// dvr_buffer_queue.h
+typedef int (*DvrWriteBufferQueueCreatePtr)(uint32_t width, uint32_t height,
+ uint32_t format,
+ uint32_t layer_count,
+ uint64_t usage, size_t capacity,
+ size_t metadata_size,
+ DvrWriteBufferQueue** queue_out);
typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
typedef ssize_t (*DvrWriteBufferQueueGetCapacityPtr)(
DvrWriteBufferQueue* write_queue);
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 72e0f67..da12c13 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -160,3 +160,6 @@
// Read buffer queue
DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd);
+
+// Create write buffer queue locally
+DVR_V1_API_ENTRY(WriteBufferQueueCreate);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index e2127f8..b3b41e2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,6 +12,36 @@
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+// Creates a write buffer queue to be used locally.
+//
+// Note that this API is mostly for testing purpose. For now there is no
+// mechanism to send a DvrWriteBufferQueue cross process. Use
+// dvrSurfaceCreateWriteBufferQueue if cross-process buffer transport is
+// intended.
+//
+// @param width The width of the buffers that this queue will produce.
+// @param height The height of buffers that this queue will produce.
+// @param format The format of the buffers that this queue will produce. This
+// must be one of the AHARDWAREBUFFER_FORMAT_XXX enums.
+// @param layer_count The number of layers of the buffers that this queue will
+// produce.
+// @param usage The usage of the buffers that this queue will produce. This
+// must a combination of the AHARDWAREBUFFER_USAGE_XXX flags.
+// @param capacity The number of buffer that this queue will allocate. Note that
+// all buffers will be allocated on create. Currently, the number of buffers
+// is the queue cannot be changed after creation though DVR API. However,
+// ANativeWindow can choose to reallocate, attach, or detach buffers from
+// a DvrWriteBufferQueue through Android platform logic.
+// @param metadata_size The size of metadata in bytes.
+// @param out_write_queue The pointer of a DvrWriteBufferQueue will be filled
+// here if the method call succeeds. The metadata size must match
+// the metadata size in dvrWriteBufferPost/dvrReadBufferAcquire.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t layer_count, uint64_t usage,
+ size_t capacity, size_t metadata_size,
+ DvrWriteBufferQueue** out_write_queue);
+
// Destroy a write buffer queue.
//
// @param write_queue The DvrWriteBufferQueue of interest.
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index f75283d..7520eee 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,24 +1,30 @@
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android-base/unique_fd.h>
#include <dvr/dvr_api.h>
#include <dvr/dvr_buffer_queue.h>
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <base/logging.h>
#include <gtest/gtest.h>
-#include "../dvr_internal.h"
-#include "../dvr_buffer_queue_internal.h"
+#include <array>
+#include <unordered_map>
-namespace android {
-namespace dvr {
+#ifndef ALOGD
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
+#endif
namespace {
static constexpr uint32_t kBufferWidth = 100;
static constexpr uint32_t kBufferHeight = 1;
static constexpr uint32_t kLayerCount = 1;
-static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
static constexpr size_t kQueueCapacity = 3;
typedef uint64_t TestMeta;
@@ -36,14 +42,6 @@
}
protected:
- void SetUp() override {
- config_builder_ = ProducerQueueConfigBuilder()
- .SetDefaultWidth(kBufferWidth)
- .SetDefaultHeight(kBufferHeight)
- .SetDefaultFormat(kBufferFormat)
- .SetMetadata<TestMeta>();
- }
-
void TearDown() override {
if (write_queue_ != nullptr) {
dvrWriteBufferQueueDestroy(write_queue_);
@@ -51,19 +49,6 @@
}
}
- void CreateWriteBufferQueue() {
- write_queue_ = new DvrWriteBufferQueue(
- ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
- ASSERT_NE(nullptr, write_queue_);
- }
-
- void AllocateBuffers(size_t buffer_count) {
- auto status = write_queue_->producer_queue()->AllocateBuffers(
- kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
- buffer_count);
- ASSERT_TRUE(status.ok());
- }
-
void HandleBufferAvailable() {
buffer_available_count_ += 1;
ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
@@ -75,22 +60,26 @@
buffer_removed_count_);
}
- ProducerQueueConfigBuilder config_builder_;
DvrWriteBufferQueue* write_queue_{nullptr};
int buffer_available_count_{0};
int buffer_removed_count_{0};
};
TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
dvrWriteBufferQueueDestroy(write_queue_);
write_queue_ = nullptr;
}
TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
@@ -99,10 +88,13 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -111,11 +103,14 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue1 = nullptr;
DvrReadBufferQueue* read_queue2 = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue1);
@@ -130,8 +125,10 @@
}
TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBuffer* read_buffer = nullptr;
DvrWriteBuffer* write_buffer = nullptr;
@@ -164,8 +161,10 @@
}
TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
static constexpr int kTimeout = 0;
DvrReadBufferQueue* read_queue = nullptr;
@@ -173,7 +172,7 @@
DvrWriteBuffer* wb = nullptr;
int fence_fd = -1;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -193,7 +192,7 @@
ASSERT_TRUE(dvrWriteBufferIsValid(wb));
ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
wb, fence_fd);
- pdx::LocalHandle release_fence(fence_fd);
+ android::base::unique_fd release_fence(fence_fd);
// Post buffer to the read_queue.
TestMeta seq = 42U;
@@ -215,7 +214,7 @@
ALOGD_IF(TRACE,
"TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
fence_fd);
- pdx::LocalHandle acquire_fence(fence_fd);
+ android::base::unique_fd acquire_fence(fence_fd);
// Release buffer to the write_queue.
ret = dvrReadBufferRelease(rb, -1);
@@ -234,40 +233,52 @@
}
TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
ANativeWindow* window = nullptr;
// The |write_queue_| doesn't have proper metadata (must be
// DvrNativeBufferMetadata) configured during creation.
- int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
+ ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
ASSERT_EQ(-EINVAL, ret);
ASSERT_EQ(nullptr, window);
+ dvrWriteBufferQueueDestroy(write_queue_);
+ write_queue_ = nullptr;
// A write queue with DvrNativeBufferMetadata should work fine.
- auto config = ProducerQueueConfigBuilder()
- .SetMetadata<DvrNativeBufferMetadata>()
- .Build();
- std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
- write_queue(
- new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
- dvrWriteBufferQueueDestroy);
- ASSERT_NE(nullptr, write_queue.get());
+ ASSERT_EQ(nullptr, write_queue_);
- ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
+ ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, write_queue_);
+
+ ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, window);
- sp<Surface> surface = static_cast<Surface*>(window);
- ASSERT_TRUE(Surface::isValid(surface));
+ // TODO(b/64723700): Remove dependencies of Android platform bits so that we
+ // can run dvr_buffer_queue-test in DTS.
+ uint32_t width = ANativeWindow_getWidth(window);
+ uint32_t height = ANativeWindow_getHeight(window);
+ uint32_t format = ANativeWindow_getFormat(window);
+ ASSERT_EQ(kBufferWidth, width);
+ ASSERT_EQ(kBufferHeight, height);
+ ASSERT_EQ(kBufferFormat, format);
}
// Create buffer queue of three buffers and dequeue three buffers out of it.
// Before each dequeue operation, we resize the buffer queue and expect the
// queue always return buffer with desired dimension.
TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
static constexpr int kTimeout = 0;
int fence_fd = -1;
@@ -281,7 +292,7 @@
AHardwareBuffer* ahb3 = nullptr;
AHardwareBuffer_Desc buffer_desc;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -314,7 +325,7 @@
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
- pdx::LocalHandle release_fence1(fence_fd);
+ android::base::unique_fd release_fence1(fence_fd);
// Check the buffer dimension.
ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
@@ -341,7 +352,7 @@
ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
fence_fd);
- pdx::LocalHandle release_fence2(fence_fd);
+ android::base::unique_fd release_fence2(fence_fd);
// Check the buffer dimension, should be new width
ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
@@ -367,7 +378,7 @@
ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
fence_fd);
- pdx::LocalHandle release_fence3(fence_fd);
+ android::base::unique_fd release_fence3(fence_fd);
// Check the buffer dimension, should be new width
ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
@@ -387,9 +398,10 @@
TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
// Overrides default queue parameters: Empty metadata.
- config_builder_.SetMetadata<void>();
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/1, /*metadata_size=*/0, &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBuffer* rb = nullptr;
DvrWriteBuffer* wb = nullptr;
@@ -416,8 +428,10 @@
}
TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/1, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBuffer* rb = nullptr;
DvrWriteBuffer* wb = nullptr;
@@ -451,11 +465,13 @@
}
TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -468,8 +484,10 @@
// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
// the corresponding AHardwareBuffer handle stays the same.
TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
int fence_fd = -1;
DvrReadBufferQueue* read_queue = nullptr;
@@ -621,6 +639,3 @@
}
} // namespace
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 8cfa86f..0f6511b 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -36,10 +36,10 @@
}
cc_binary {
- name: "servicetool",
+ name: "pdx_tool",
defaults: ["pdx_default_transport_compiler_defaults"],
srcs: [
- "servicetool.cpp",
+ "pdx_tool.cpp",
],
shared_libs: [
"liblog",
diff --git a/libs/vr/libpdx_default_transport/servicetool.cpp b/libs/vr/libpdx_default_transport/pdx_tool.cpp
similarity index 100%
rename from libs/vr/libpdx_default_transport/servicetool.cpp
rename to libs/vr/libpdx_default_transport/pdx_tool.cpp
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index f350762..af18e21 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -243,18 +243,16 @@
surface_status.GetErrorMessage().c_str());
return ErrorStatus(surface_status.error());
}
+ auto surface = surface_status.take();
+ message.SetChannel(surface);
- SurfaceType surface_type = surface_status.get()->surface_type();
- display::SurfaceUpdateFlags update_flags =
- surface_status.get()->update_flags();
- display::SurfaceInfo surface_info{surface_status.get()->surface_id(),
- surface_status.get()->visible(),
- surface_status.get()->z_order()};
+ // Update the surface with the attributes supplied with the create call. For
+ // application surfaces this has the side effect of notifying the display
+ // manager of the new surface. For direct surfaces, this may trigger a mode
+ // change, depending on the value of the visible attribute.
+ surface->OnSetAttributes(message, attributes);
- message.SetChannel(surface_status.take());
-
- SurfaceUpdated(surface_type, update_flags);
- return {surface_info};
+ return {{surface->surface_id(), surface->visible(), surface->z_order()}};
}
void DisplayService::SurfaceUpdated(SurfaceType surface_type,
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 4852fab..6853781 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -26,14 +26,12 @@
DisplaySurface::DisplaySurface(DisplayService* service,
SurfaceType surface_type, int surface_id,
- int process_id, int user_id,
- const display::SurfaceAttributes& attributes)
+ int process_id, int user_id)
: service_(service),
surface_type_(surface_type),
surface_id_(surface_id),
process_id_(process_id),
user_id_(user_id),
- attributes_(attributes),
update_flags_(display::SurfaceUpdateFlags::NewSurface) {}
DisplaySurface::~DisplaySurface() {
@@ -471,8 +469,8 @@
if (direct) {
const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
if (trusted) {
- return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface(
- service, surface_id, process_id, user_id, attributes)}};
+ return {std::shared_ptr<DisplaySurface>{
+ new DirectDisplaySurface(service, surface_id, process_id, user_id)}};
} else {
ALOGE(
"DisplaySurface::Create: Direct surfaces may only be created by "
@@ -482,7 +480,7 @@
}
} else {
return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface(
- service, surface_id, process_id, user_id, attributes)}};
+ service, surface_id, process_id, user_id)}};
}
}
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index 7a0fb18..c8b1a07 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -53,8 +53,7 @@
protected:
DisplaySurface(DisplayService* service, SurfaceType surface_type,
- int surface_id, int process_id, int user_id,
- const display::SurfaceAttributes& attributes);
+ int surface_id, int process_id, int user_id);
// Utility to retrieve a shared pointer to this channel as the desired derived
// type.
@@ -119,10 +118,9 @@
class ApplicationDisplaySurface : public DisplaySurface {
public:
ApplicationDisplaySurface(DisplayService* service, int surface_id,
- int process_id, int user_id,
- const display::SurfaceAttributes& attributes)
+ int process_id, int user_id)
: DisplaySurface(service, SurfaceType::Application, surface_id,
- process_id, user_id, attributes) {}
+ process_id, user_id) {}
std::shared_ptr<ConsumerQueue> GetQueue(int32_t queue_id);
std::vector<int32_t> GetQueueIds() const override;
@@ -140,12 +138,11 @@
class DirectDisplaySurface : public DisplaySurface {
public:
DirectDisplaySurface(DisplayService* service, int surface_id, int process_id,
- int user_id,
- const display::SurfaceAttributes& attributes)
+ int user_id)
: DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
- user_id, attributes),
+ user_id),
acquired_buffers_(kMaxPostedBuffers),
- metadata_(nullptr){}
+ metadata_(nullptr) {}
std::vector<int32_t> GetQueueIds() const override;
bool IsBufferAvailable();
bool IsBufferPosted();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4edde14..038ece2 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -202,9 +202,11 @@
mFrameTracker.logAndResetStats(mName);
#ifdef USE_HWC2
- ALOGE_IF(!mHwcLayers.empty(),
- "Found stale hardware composer layers when destroying "
- "surface flinger layer");
+ if (!mHwcLayers.empty()) {
+ ALOGE("Found stale hardware composer layers when destroying "
+ "surface flinger layer %s", mName.string());
+ destroyAllHwcLayers();
+ }
#endif
}
@@ -293,20 +295,27 @@
}
}
-// called with SurfaceFlinger::mStateLock from the drawing thread after
-// the layer has been remove from the current state list (and just before
-// it's removed from the drawing state list)
-void Layer::onRemoved() {
+void Layer::onRemovedFromCurrentState() {
+ // the layer is removed from SF mCurrentState to mLayersPendingRemoval
+
if (mCurrentState.zOrderRelativeOf != nullptr) {
sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
if (strongRelative != nullptr) {
strongRelative->removeZOrderRelative(this);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
}
mCurrentState.zOrderRelativeOf = nullptr;
}
- mSurfaceFlingerConsumer->abandon();
+ for (const auto& child : mCurrentChildren) {
+ child->onRemovedFromCurrentState();
+ }
+}
+void Layer::onRemoved() {
+ // the layer is removed from SF mLayersPendingRemoval
+
+ mSurfaceFlingerConsumer->abandon();
#ifdef USE_HWC2
destroyAllHwcLayers();
#endif
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 222718b..c34d8a0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -419,8 +419,14 @@
bool isPotentialCursor() const { return mPotentialCursor;}
/*
- * called with the state lock when the surface is removed from the
- * current list
+ * called with the state lock from a binder thread when the layer is
+ * removed from the current list to the pending removal list
+ */
+ void onRemovedFromCurrentState();
+
+ /*
+ * called with the state lock from the main thread when the layer is
+ * removed from the pending removal list
*/
void onRemoved();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4aaa8c0..7363464 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -391,20 +391,10 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- sp<LambdaMessage> bootFinished = new LambdaMessage([&]() {
- mBootFinished = true;
-
+ sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
readPersistentProperties();
-
-#ifdef USE_HWC2
- sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
- if (hw->getWideColorSupport()) {
- hw->setCompositionDataSpace(HAL_DATASPACE_V0_SRGB);
- setActiveColorModeInternal(hw, HAL_COLOR_MODE_SRGB);
- }
-#endif
});
- postMessageAsync(bootFinished);
+ postMessageAsync(readProperties);
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -569,7 +559,7 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs);
+ ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
Mutex::Autolock _l(mStateLock);
@@ -1231,7 +1221,11 @@
token, fbs, producer, mRenderEngine->getEGLConfig(),
hasWideColorModes && hasWideColorDisplay);
mDisplays.add(token, hw);
- setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE);
+ android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
+ if (hasWideColorModes && hasWideColorDisplay) {
+ defaultColorMode = HAL_COLOR_MODE_SRGB;
+ }
+ setActiveColorModeInternal(hw, defaultColorMode);
hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
// Add the primary display token to mDrawingState so we don't try to
@@ -1874,12 +1868,7 @@
}
newColorMode = pickColorMode(newDataSpace);
- // We want the color mode of the boot animation to match that of the bootloader
- // To achieve this we suppress color mode changes until after the boot animation
- if (mBootFinished) {
- setActiveColorModeInternal(displayDevice, newColorMode);
- displayDevice->setCompositionDataSpace(newDataSpace);
- }
+ setActiveColorModeInternal(displayDevice, newColorMode);
}
}
@@ -2790,6 +2779,7 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
mNumLayers -= 1 + layer->getChildrenCount();
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e5bb228..b28fe68 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2382,6 +2382,7 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
mNumLayers -= 1 + layer->getChildrenCount();
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 4b9fbe0..4c26671 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -22,13 +22,15 @@
using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
namespace {
const char kCpuSetBasePath[] = "/dev/cpuset";
+const char kRootCpuSet[] = "/";
+
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
@@ -123,22 +125,22 @@
// 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>>>;
+ 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>>;
+ 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_ = {
+ scheduler_policies_ = {
{"audio:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
@@ -183,12 +185,14 @@
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 2,
- .permission_check = AllowRootSystemTrusted::Check}},
+ .permission_check = AllowRootSystemTrusted::Check,
+ "/system/performance"}},
{"vr:app:render",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 1,
- .permission_check = AllowRootSystemTrusted::Check}},
+ .permission_check = AllowRootSystemTrusted::Check,
+ "/application/performance"}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_NORMAL,
@@ -219,14 +223,80 @@
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);
+
+ Task task(task_id);
+ if (!task) {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Unable to access /proc/%d "
+ "to gather task information.",
+ task_id);
+ return ErrorStatus(EINVAL);
+ }
+
+ auto search = scheduler_policies_.find(scheduler_policy);
+ if (search != scheduler_policies_.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);
+
+ // Get the thread group's cpu set. Policies that do not specify a cpuset
+ // should default to this cpuset.
+ std::string thread_group_cpuset;
+ Task thread_group{task.thread_group_id()};
+ if (thread_group) {
+ thread_group_cpuset = thread_group.GetCpuSetPath();
+ } else {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Failed to get thread "
+ "group tgid=%d for task_id=%d",
+ task.thread_group_id(), task_id);
+ thread_group_cpuset = kRootCpuSet;
+ }
+
+ std::string target_cpuset;
+ if (config.cpuset.empty()) {
+ target_cpuset = thread_group_cpuset;
+ } else {
+ target_cpuset = config.cpuset;
+ }
+ ALOGI("PerformanceService::OnSetSchedulerPolicy: Using cpuset=%s",
+ target_cpuset.c_str());
+
+ auto target_set = cpuset_.Lookup(target_cpuset);
+ if (target_set) {
+ auto attach_status = target_set->AttachTask(task_id);
+ ALOGW_IF(!attach_status,
+ "PerformanceService::OnSetSchedulerPolicy: Failed to attach "
+ "task=%d to cpuset=%s: %s",
+ task_id, target_cpuset.c_str(),
+ attach_status.GetErrorMessage().c_str());
+ } else {
+ ALOGW(
+ "PerformanceService::OnSetSchedulerPolicy: Failed to lookup "
+ "cpuset=%s",
+ target_cpuset.c_str());
+ }
+
+ 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);
+ return {};
+ } else {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Invalid scheduler_policy=%s "
+ "requested by task=%d.",
+ scheduler_policy.c_str(), task_id);
+ return ErrorStatus(EINVAL);
+ }
}
Status<void> PerformanceService::OnSetCpuPartition(
@@ -259,8 +329,8 @@
if (!task)
return ErrorStatus(EINVAL);
- auto search = scheduler_classes_.find(scheduler_class);
- if (search != scheduler_classes_.end()) {
+ auto search = scheduler_policies_.find(scheduler_class);
+ if (search != scheduler_policies_.end()) {
auto config = search->second;
// Make sure the sending process is allowed to make the requested change to
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index b28d94a..6b519ab 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -44,13 +44,13 @@
int sched_fifo_min_priority_;
int sched_fifo_max_priority_;
- // Scheduler class config type.
- struct SchedulerClassConfig {
+ struct SchedulerPolicyConfig {
unsigned long timer_slack;
int scheduler_policy;
int priority;
std::function<bool(const pdx::Message& message, const Task& task)>
permission_check;
+ std::string cpuset;
// Check the permisison of the given task to use this scheduler class. If a
// permission check function is not set then operations are only allowed on
@@ -65,7 +65,7 @@
}
};
- std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+ std::unordered_map<std::string, SchedulerPolicyConfig> scheduler_policies_;
std::function<bool(const pdx::Message& message, const Task& task)>
partition_permission_check_;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 274a1b3..4065785 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,24 +1,65 @@
#include <errno.h>
#include <sched.h>
+#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <condition_variable>
#include <cstdlib>
+#include <iostream>
#include <mutex>
+#include <sstream>
#include <thread>
+#include <utility>
+#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
+#include "stdio_filebuf.h"
+#include "string_trim.h"
+#include "unique_file.h"
+
+using android::dvr::Trim;
+using android::dvr::UniqueFile;
+using android::dvr::stdio_filebuf;
+
namespace {
const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
+const char kProcBase[] = "/proc";
+
+std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id,
+ const std::string& name) {
+ std::ostringstream stream;
+ stream << kProcBase << "/" << task_id << "/" << name;
+
+ UniqueFile file{fopen(stream.str().c_str(), "r")};
+ const int error = file ? 0 : errno;
+ return {std::move(file), error};
+}
+
+std::string GetTaskCpuSet(pid_t task_id) {
+ int error;
+ UniqueFile file;
+
+ std::tie(file, error) = OpenTaskFile(task_id, "cpuset");
+ if (!file)
+ return std::string("errno:") + strerror(error);
+
+ stdio_filebuf<char> filebuf(file.get());
+ std::istream file_stream(&filebuf);
+
+ std::string line;
+ std::getline(file_stream, line);
+ return Trim(line);
+}
+
} // anonymous namespace
-TEST(DISABLED_PerformanceTest, SetCpuPartition) {
+TEST(PerformanceTest, SetCpuPartition) {
int error;
// Test setting the the partition for the current task.
@@ -59,13 +100,6 @@
}
thread.join();
- // Test setting the partition for a task that isn't valid using
- // the task id of the thread that we just joined. Technically the
- // id could wrap around by the time we get here, but this is
- // extremely unlikely.
- error = dvrSetCpuPartition(task_id, "/application");
- EXPECT_EQ(-EINVAL, error);
-
// Test setting the partition for a task that doesn't belong to us.
error = dvrSetCpuPartition(1, "/application");
EXPECT_EQ(-EINVAL, error);
@@ -73,6 +107,10 @@
// Test setting the partition to one that doesn't exist.
error = dvrSetCpuPartition(0, "/foobar");
EXPECT_EQ(-ENOENT, error);
+
+ // Set the test back to the root partition.
+ error = dvrSetCpuPartition(0, "/");
+ EXPECT_EQ(0, error);
}
TEST(PerformanceTest, SetSchedulerClass) {
@@ -96,8 +134,6 @@
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;
@@ -115,6 +151,50 @@
error = dvrSetSchedulerPolicy(0, "foobar");
EXPECT_EQ(-EINVAL, error);
+
+ // Set the test back to the root partition.
+ error = dvrSetCpuPartition(0, "/");
+ EXPECT_EQ(0, error);
+
+ const std::string original_cpuset = GetTaskCpuSet(gettid());
+ EXPECT_EQ("/", original_cpuset);
+
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+ const std::string new_cpuset = GetTaskCpuSet(gettid());
+ EXPECT_NE(original_cpuset, new_cpuset);
+
+ // The cpuset for the thread group is now new_cpuset. Scheduler profiles that
+ // do not specify a cpuset should not change the cpuset of a thread, except to
+ // restore it to the thread group cpuset.
+ std::string thread_original_cpuset;
+ std::string thread_new_cpuset;
+ std::string thread_final_cpuset;
+
+ std::thread thread{
+ [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() {
+ thread_original_cpuset = GetTaskCpuSet(gettid());
+
+ int error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ thread_new_cpuset = GetTaskCpuSet(gettid());
+
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ thread_final_cpuset = GetTaskCpuSet(gettid());
+ }};
+ thread.join();
+
+ EXPECT_EQ(new_cpuset, thread_original_cpuset);
+ EXPECT_NE(new_cpuset, thread_new_cpuset);
+ EXPECT_EQ(new_cpuset, thread_final_cpuset);
+
+ error = dvrSetCpuPartition(0, original_cpuset.c_str());
+ EXPECT_EQ(0, error);
}
TEST(PerformanceTest, SchedulerClassResetOnFork) {
@@ -424,11 +504,11 @@
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics");
- EXPECT_EQ(0, error);
+ EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
- EXPECT_EQ(0, error);
+ EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
- EXPECT_EQ(0, error);
+ EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index 1175a7b..c2f078e 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -48,15 +48,18 @@
thread_count_(0),
cpus_allowed_mask_(0) {
task_fd_ = OpenTaskDirectory(task_id_);
- ALOGE_IF(task_fd_.get() < 0,
+ const int error = errno;
+ ALOGE_IF(task_fd_.get() < 0 && error != EACCES,
"Task::Task: Failed to open task directory for task_id=%d: %s",
- task_id, strerror(errno));
+ task_id, strerror(error));
- ReadStatusFields();
-
- ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
- task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
- cpus_allowed_mask_);
+ if (IsValid()) {
+ ReadStatusFields();
+ ALOGD_IF(TRACE,
+ "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
+ task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
+ cpus_allowed_mask_);
+ }
}
base::unique_fd Task::OpenTaskFile(const std::string& name) const {