1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "android.hardware.automotive.evs@1.1-service"
18
19 #include "EvsDisplay.h"
20
21 #include <ui/GraphicBufferAllocator.h>
22 #include <ui/GraphicBufferMapper.h>
23
24 using ::android::frameworks::automotive::display::V1_0::HwDisplayConfig;
25 using ::android::frameworks::automotive::display::V1_0::HwDisplayState;
26
27 namespace android {
28 namespace hardware {
29 namespace automotive {
30 namespace evs {
31 namespace V1_1 {
32 namespace implementation {
33
34
EvsDisplay()35 EvsDisplay::EvsDisplay() {
36 EvsDisplay(nullptr, 0);
37 }
38
39
EvsDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy,uint64_t displayId)40 EvsDisplay::EvsDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId)
41 : mDisplayProxy(pDisplayProxy),
42 mDisplayId(displayId) {
43 ALOGD("EvsDisplay instantiated");
44
45 // Set up our self description
46 // NOTE: These are arbitrary values chosen for testing
47 mInfo.displayId = "Mock Display";
48 mInfo.vendorFlags = 3870;
49
50 // Assemble the buffer description we'll use for our render target
51 mBuffer.width = 320;
52 mBuffer.height = 240;
53 mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;
54 mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
55 mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition
56 mBuffer.pixelSize = 4;
57 }
58
59
~EvsDisplay()60 EvsDisplay::~EvsDisplay() {
61 ALOGD("EvsDisplay being destroyed");
62 forceShutdown();
63 }
64
65
66 /**
67 * This gets called if another caller "steals" ownership of the display
68 */
forceShutdown()69 void EvsDisplay::forceShutdown()
70 {
71 ALOGD("EvsDisplay forceShutdown");
72 std::lock_guard<std::mutex> lock(mAccessLock);
73
74 // If the buffer isn't being held by a remote client, release it now as an
75 // optimization to release the resources more quickly than the destructor might
76 // get called.
77 if (mBuffer.memHandle) {
78 // Report if we're going away while a buffer is outstanding
79 if (mFrameBusy) {
80 ALOGE("EvsDisplay going down while client is holding a buffer");
81 }
82
83 // Drop the graphics buffer we've been using
84 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
85 alloc.free(mBuffer.memHandle);
86 mBuffer.memHandle = nullptr;
87 }
88
89 // Put this object into an unrecoverable error state since somebody else
90 // is going to own the display now.
91 mRequestedState = DisplayState::DEAD;
92 }
93
94
95 /**
96 * Returns basic information about the EVS display provided by the system.
97 * See the description of the DisplayDesc structure for details.
98 */
getDisplayInfo(getDisplayInfo_cb _hidl_cb)99 Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
100 ALOGD("getDisplayInfo");
101
102 // Send back our self description
103 _hidl_cb(mInfo);
104 return Void();
105 }
106
107
108 /**
109 * Clients may set the display state to express their desired state.
110 * The HAL implementation must gracefully accept a request for any state
111 * while in any other state, although the response may be to ignore the request.
112 * The display is defined to start in the NOT_VISIBLE state upon initialization.
113 * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
114 * then begin providing video. When the display is no longer required, the client
115 * is expected to request the NOT_VISIBLE state after passing the last video frame.
116 */
setDisplayState(DisplayState state)117 Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
118 ALOGD("setDisplayState");
119 std::lock_guard<std::mutex> lock(mAccessLock);
120
121 if (mRequestedState == DisplayState::DEAD) {
122 // This object no longer owns the display -- it's been superceeded!
123 return EvsResult::OWNERSHIP_LOST;
124 }
125
126 // Ensure we recognize the requested state so we don't go off the rails
127 if (state < DisplayState::NUM_STATES) {
128 // Record the requested state
129 mRequestedState = state;
130 return EvsResult::OK;
131 }
132 else {
133 // Turn off the display if asked for an unrecognized state
134 mRequestedState = DisplayState::NOT_VISIBLE;
135 return EvsResult::INVALID_ARG;
136 }
137 }
138
139
140 /**
141 * The HAL implementation should report the actual current state, which might
142 * transiently differ from the most recently requested state. Note, however, that
143 * the logic responsible for changing display states should generally live above
144 * the device layer, making it undesirable for the HAL implementation to
145 * spontaneously change display states.
146 */
getDisplayState()147 Return<DisplayState> EvsDisplay::getDisplayState() {
148 ALOGD("getDisplayState");
149 std::lock_guard<std::mutex> lock(mAccessLock);
150
151 return mRequestedState;
152 }
153
154
155 /**
156 * This call returns a handle to a frame buffer associated with the display.
157 * This buffer may be locked and written to by software and/or GL. This buffer
158 * must be returned via a call to returnTargetBufferForDisplay() even if the
159 * display is no longer visible.
160 */
161 // TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
getTargetBuffer(getTargetBuffer_cb _hidl_cb)162 Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
163 ALOGD("getTargetBuffer");
164 std::lock_guard<std::mutex> lock(mAccessLock);
165
166 if (mRequestedState == DisplayState::DEAD) {
167 ALOGE("Rejecting buffer request from object that lost ownership of the display.");
168 BufferDesc_1_0 nullBuff = {};
169 _hidl_cb(nullBuff);
170 return Void();
171 }
172
173 // If we don't already have a buffer, allocate one now
174 if (!mBuffer.memHandle) {
175 // Allocate the buffer that will hold our displayable image
176 buffer_handle_t handle = nullptr;
177 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
178 status_t result = alloc.allocate(
179 mBuffer.width, mBuffer.height, mBuffer.format, 1, mBuffer.usage,
180 &handle, &mBuffer.stride, 0, "EvsDisplay");
181 if (result != NO_ERROR) {
182 ALOGE("Error %d allocating %d x %d graphics buffer",
183 result, mBuffer.width, mBuffer.height);
184 BufferDesc_1_0 nullBuff = {};
185 _hidl_cb(nullBuff);
186 return Void();
187 }
188 if (!handle) {
189 ALOGE("We didn't get a buffer handle back from the allocator");
190 BufferDesc_1_0 nullBuff = {};
191 _hidl_cb(nullBuff);
192 return Void();
193 }
194
195 mBuffer.memHandle = handle;
196 mFrameBusy = false;
197 ALOGD("Allocated new buffer %p with stride %u",
198 mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
199 }
200
201 // Do we have a frame available?
202 if (mFrameBusy) {
203 // This means either we have a 2nd client trying to compete for buffers
204 // (an unsupported mode of operation) or else the client hasn't returned
205 // a previously issued buffer yet (they're behaving badly).
206 // NOTE: We have to make the callback even if we have nothing to provide
207 ALOGE("getTargetBuffer called while no buffers available.");
208 BufferDesc_1_0 nullBuff = {};
209 _hidl_cb(nullBuff);
210 return Void();
211 } else {
212 // Mark our buffer as busy
213 mFrameBusy = true;
214
215 // Send the buffer to the client
216 ALOGD("Providing display buffer handle %p as id %d",
217 mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
218 _hidl_cb(mBuffer);
219 return Void();
220 }
221 }
222
223
224 /**
225 * This call tells the display that the buffer is ready for display.
226 * The buffer is no longer valid for use by the client after this call.
227 */
returnTargetBufferForDisplayImpl(const uint32_t bufferId,const buffer_handle_t memHandle)228 Return<EvsResult> EvsDisplay::returnTargetBufferForDisplayImpl(const uint32_t bufferId, const buffer_handle_t memHandle) {
229 ALOGD("returnTargetBufferForDisplay %p", memHandle);
230 std::lock_guard<std::mutex> lock(mAccessLock);
231
232 // Nobody should call us with a null handle
233 if (!memHandle) {
234 ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
235 return EvsResult::INVALID_ARG;
236 }
237 if (bufferId != mBuffer.bufferId) {
238 ALOGE ("Got an unrecognized frame returned.\n");
239 return EvsResult::INVALID_ARG;
240 }
241 if (!mFrameBusy) {
242 ALOGE ("A frame was returned with no outstanding frames.\n");
243 return EvsResult::BUFFER_NOT_AVAILABLE;
244 }
245
246 mFrameBusy = false;
247
248 // If we've been displaced by another owner of the display, then we can't do anything else
249 if (mRequestedState == DisplayState::DEAD) {
250 return EvsResult::OWNERSHIP_LOST;
251 }
252
253 // If we were waiting for a new frame, this is it!
254 if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
255 mRequestedState = DisplayState::VISIBLE;
256 }
257
258 // Validate we're in an expected state
259 if (mRequestedState != DisplayState::VISIBLE) {
260 // We shouldn't get frames back when we're not visible.
261 ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
262 } else {
263 // This is where the buffer would be made visible.
264 // For now we simply validate it has the data we expect in it by reading it back
265
266 // Lock our display buffer for reading
267 uint32_t* pixels = nullptr;
268 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
269 mapper.lock(mBuffer.memHandle,
270 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
271 android::Rect(mBuffer.width, mBuffer.height),
272 (void **)&pixels);
273
274 // If we failed to lock the pixel buffer, we're about to crash, but log it first
275 if (!pixels) {
276 ALOGE("Display failed to gain access to image buffer for reading");
277 }
278
279 // Check the test pixels
280 bool frameLooksGood = true;
281 for (unsigned row = 0; row < mBuffer.height; row++) {
282 for (unsigned col = 0; col < mBuffer.width; col++) {
283 // Index into the row to check the pixel at this column.
284 // We expect 0xFF in the LSB channel, a vertical gradient in the
285 // second channel, a horitzontal gradient in the third channel, and
286 // 0xFF in the MSB.
287 // The exception is the very first 32 bits which is used for the
288 // time varying frame signature to avoid getting fooled by a static image.
289 uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
290 ((row & 0xFF) << 8) | // vertical gradient
291 ((col & 0xFF) << 16); // horizontal gradient
292 if ((row | col) == 0) {
293 // we'll check the "uniqueness" of the frame signature below
294 continue;
295 }
296 // Walk across this row (we'll step rows below)
297 uint32_t receivedPixel = pixels[col];
298 if (receivedPixel != expectedPixel) {
299 ALOGE("Pixel check mismatch in frame buffer");
300 frameLooksGood = false;
301 break;
302 }
303 }
304
305 if (!frameLooksGood) {
306 break;
307 }
308
309 // Point to the next row (NOTE: gralloc reports stride in units of pixels)
310 pixels = pixels + mBuffer.stride;
311 }
312
313 // Ensure we don't see the same buffer twice without it being rewritten
314 static uint32_t prevSignature = ~0;
315 uint32_t signature = pixels[0] & 0xFF;
316 if (prevSignature == signature) {
317 frameLooksGood = false;
318 ALOGE("Duplicate, likely stale frame buffer detected");
319 }
320
321
322 // Release our output buffer
323 mapper.unlock(mBuffer.memHandle);
324
325 if (!frameLooksGood) {
326 return EvsResult::UNDERLYING_SERVICE_ERROR;
327 }
328 }
329
330 return EvsResult::OK;
331 }
332
333
returnTargetBufferForDisplay(const BufferDesc_1_0 & buffer)334 Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer) {
335 return returnTargetBufferForDisplayImpl(buffer.bufferId, buffer.memHandle);
336 }
337
338
getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb)339 Return<void> EvsDisplay::getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) {
340 if (mDisplayProxy != nullptr) {
341 return mDisplayProxy->getDisplayInfo(mDisplayId, _info_cb);
342 } else {
343 HwDisplayConfig nullConfig;
344 HwDisplayState nullState;
345 _info_cb(nullConfig, nullState);
346 return Void();
347 }
348 }
349
350
351 } // namespace implementation
352 } // namespace V1_1
353 } // namespace evs
354 } // namespace automotive
355 } // namespace hardware
356 } // namespace android
357