blob: fd1c5820e73370255edda6516ba44eaef4a494c6 [file] [log] [blame]
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08001#include "screenshot_service.h"
2
3#include <utils/Trace.h>
4
5#include <pdx/default_transport/service_endpoint.h>
Leandro Gracia Gil4766e2a2017-01-27 18:14:42 -08006#include <private/android_filesystem_config.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08007#include <private/dvr/display_types.h>
Leandro Gracia Gil4766e2a2017-01-27 18:14:42 -08008#include <private/dvr/trusted_uids.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08009
10using android::pdx::Message;
11using android::pdx::MessageInfo;
12using android::pdx::default_transport::Endpoint;
13using android::pdx::rpc::DispatchRemoteMethod;
14using android::pdx::rpc::RemoteMethodError;
15using android::pdx::rpc::RemoteMethodReturn;
16
17namespace android {
18namespace dvr {
19
20ScreenshotService::~ScreenshotService() { instance_ = nullptr; }
21
22int ScreenshotService::HandleMessage(pdx::Message& message) {
23 switch (message.GetOp()) {
24 case DisplayScreenshotRPC::GetFormat::Opcode:
25 DispatchRemoteMethod<DisplayScreenshotRPC::GetFormat>(
26 *this, &ScreenshotService::OnGetFormat, message);
27 return 0;
28
29 case DisplayScreenshotRPC::TakeScreenshot::Opcode:
30 DispatchRemoteMethod<DisplayScreenshotRPC::TakeScreenshot>(
31 *this, &ScreenshotService::OnTakeScreenshot, message);
32 return 0;
33
34 default:
35 return Service::HandleMessage(message);
36 }
37}
38
39int ScreenshotService::OnGetFormat(pdx::Message&) {
40 return HAL_PIXEL_FORMAT_RGB_888;
41}
42
43ScreenshotData ScreenshotService::OnTakeScreenshot(pdx::Message& message,
44 int layer_index) {
Leandro Gracia Gil4766e2a2017-01-27 18:14:42 -080045 // Also allow AID_SHELL to support vrscreencap commands.
46 if (message.GetEffectiveUserId() != AID_SHELL &&
47 !IsTrustedUid(message.GetEffectiveUserId())) {
48 REPLY_ERROR_RETURN(message, EACCES, {});
49 }
50
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080051 AddWaiter(std::move(message), layer_index);
52 return {};
53}
54
55void ScreenshotService::AddWaiter(pdx::Message&& message, int layer_index) {
56 std::lock_guard<std::mutex> lock(mutex_);
57 waiters_.emplace_back(std::move(message), layer_index);
58}
59
60void ScreenshotService::TakeIfNeeded(
61 std::array<Layer*, HardwareComposer::kMaxHardwareLayers>& hw_layers,
62 Compositor& compositor) {
63 std::lock_guard<std::mutex> lock(mutex_);
64
65 // Send the buffer contents to all of our waiting clients.
66 for (auto& waiter : waiters_) {
67 if (waiter.IsDone())
68 continue;
69
70 if (waiter.layer_index() == 0) {
71 ALOGE(
72 "ScreenshotService::TakeIfNeeded: Capturing the composited display "
73 "output is not yet supported.");
74
75 waiter.Error(EINVAL);
76 continue;
77 }
78
79 if (waiter.layer_index() > 0) {
80 // Check for hardware layer screenshot requests.
81 // Hardware layers are requested with positive indices starting at 1.
82 const size_t layer_index = static_cast<size_t>(waiter.layer_index() - 1);
83
84 if (layer_index >= hw_layers.size()) {
85 waiter.Error(EINVAL);
86 continue;
87 }
88
89 auto buffer = hw_layers[layer_index]->GetBuffer();
90 if (!buffer) {
91 waiter.Error(ENOBUFS);
92 continue;
93 }
94
95 auto data = compositor.ReadBufferPixels(buffer);
96 if (data.empty()) {
97 waiter.Error(ENOBUFS);
98 continue;
99 }
100
101 Take(&waiter, data.data(), buffer->width(), buffer->height(),
102 buffer->width());
103 } else {
104 // Check for compositor input layer screenshot requests.
105 // Prewarp surfaces are requested with negative indices starting at -1.
106 const size_t layer_index = static_cast<size_t>(-waiter.layer_index() - 1);
107
108 if (layer_index >= compositor.GetLayerCount()) {
109 waiter.Error(EINVAL);
110 continue;
111 }
112
113 int width = 0;
114 int height = 0;
115 auto data = compositor.ReadLayerPixels(layer_index, &width, &height);
116 if (data.empty()) {
117 waiter.Error(ENOBUFS);
118 continue;
119 }
120
121 Take(&waiter, data.data(), width, height, width);
122 }
123 }
124
125 // Reply with error to requests that did not match up with a source layer.
126 for (auto& waiter : waiters_) {
127 if (!waiter.IsDone())
128 waiter.Error(EAGAIN);
129 }
130 waiters_.clear();
131}
132
133void ScreenshotWaiter::Reply(const ScreenshotData& screenshot) {
134 ALOGI("Returning screenshot: size=%zu recv_size=%zu",
135 screenshot.buffer.size(), message_.GetReceiveLength());
136 RemoteMethodReturn<DisplayScreenshotRPC::TakeScreenshot>(message_,
137 screenshot);
138}
139
140void ScreenshotWaiter::Error(int error) { RemoteMethodError(message_, error); }
141
142void ScreenshotService::Take(ScreenshotWaiter* waiter, const void* rgba_data,
143 int32_t width, int32_t height, int buffer_stride) {
144 ATRACE_NAME(__PRETTY_FUNCTION__);
145
146 bool is_portrait = height > width;
147 if (is_portrait) {
148 std::swap(width, height);
149 }
150 int response_stride = width;
151
152 // Convert from RGBA to RGB and if in portrait, rotates to landscape; store
153 // the result in the response buffer.
154 ScreenshotData screenshot{width, height,
155 std::vector<uint8_t>(width * height * 3)};
156
157 const auto rgba_bytes = static_cast<const uint8_t*>(rgba_data);
158 for (int j = 0; j < height; ++j) {
159 for (int i = 0; i < width; ++i) {
160 // If the screenshot is in portrait mode, rotate into landscape mode.
161 const int response_index = is_portrait
162 ? (height - j - 1) * response_stride + i
163 : j * response_stride + i;
164 const int buffer_index =
165 is_portrait ? i * buffer_stride + j : j * buffer_stride + i;
166 screenshot.buffer[response_index * 3 + 0] =
167 rgba_bytes[buffer_index * 4 + 0];
168 screenshot.buffer[response_index * 3 + 1] =
169 rgba_bytes[buffer_index * 4 + 1];
170 screenshot.buffer[response_index * 3 + 2] =
171 rgba_bytes[buffer_index * 4 + 2];
172 }
173 }
174
175 waiter->Reply(screenshot);
176}
177
178ScreenshotService::ScreenshotService()
179 : BASE("ScreenshotService",
180 Endpoint::Create(DisplayScreenshotRPC::kClientPath)) {
181 instance_ = this;
182}
183
184ScreenshotService* ScreenshotService::GetInstance() { return instance_; }
185
186ScreenshotService* ScreenshotService::instance_ = nullptr;
187
188} // namespace dvr
189} // namespace android