1 /*
2  * Copyright (C) 2018 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 "ExtCamDevSsn@3.5"
18 #include <android/log.h>
19 
20 #include <utils/Trace.h>
21 #include "ExternalCameraDeviceSession.h"
22 
23 namespace android {
24 namespace hardware {
25 namespace camera {
26 namespace device {
27 namespace V3_5 {
28 namespace implementation {
29 
ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback> & callback,const ExternalCameraConfig & cfg,const std::vector<SupportedV4L2Format> & sortedFormats,const CroppingType & croppingType,const common::V1_0::helper::CameraMetadata & chars,const std::string & cameraId,unique_fd v4l2Fd)30 ExternalCameraDeviceSession::ExternalCameraDeviceSession(
31         const sp<V3_2::ICameraDeviceCallback>& callback,
32         const ExternalCameraConfig& cfg,
33         const std::vector<SupportedV4L2Format>& sortedFormats,
34         const CroppingType& croppingType,
35         const common::V1_0::helper::CameraMetadata& chars,
36         const std::string& cameraId,
37         unique_fd v4l2Fd) :
38         V3_4::implementation::ExternalCameraDeviceSession(
39                 callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
40 
41     mCallback_3_5 = nullptr;
42 
43     auto castResult = V3_5::ICameraDeviceCallback::castFrom(callback);
44     if (castResult.isOk()) {
45         sp<V3_5::ICameraDeviceCallback> callback3_5 = castResult;
46         if (callback3_5 != nullptr) {
47             mCallback_3_5 = callback3_5;
48         }
49     }
50 
51     if (mCallback_3_5 != nullptr) {
52         mSupportBufMgr = true;
53     }
54 }
55 
~ExternalCameraDeviceSession()56 ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
57     closeOutputThreadImpl();
58 }
59 
configureStreams_3_5(const StreamConfiguration & requestedConfiguration,ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb)60 Return<void> ExternalCameraDeviceSession::configureStreams_3_5(
61         const StreamConfiguration& requestedConfiguration,
62         ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb)  {
63     return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb);
64 }
65 
signalStreamFlush(const hidl_vec<int32_t> &,uint32_t)66 Return<void> ExternalCameraDeviceSession::signalStreamFlush(
67         const hidl_vec<int32_t>& /*streamIds*/, uint32_t /*streamConfigCounter*/) {
68     return Void();
69 }
70 
importRequestLocked(const CaptureRequest & request,hidl_vec<buffer_handle_t * > & allBufPtrs,hidl_vec<int> & allFences)71 Status ExternalCameraDeviceSession::importRequestLocked(
72         const CaptureRequest& request,
73         hidl_vec<buffer_handle_t*>& allBufPtrs,
74         hidl_vec<int>& allFences) {
75     if (mSupportBufMgr) {
76         return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true);
77     }
78     return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false);
79 }
80 
81 
BufferRequestThread(wp<OutputThreadInterface> parent,sp<V3_5::ICameraDeviceCallback> callbacks)82 ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
83         wp<OutputThreadInterface> parent,
84         sp<V3_5::ICameraDeviceCallback> callbacks) :
85         mParent(parent),
86         mCallbacks(callbacks) {}
87 
requestBufferStart(const std::vector<HalStreamBuffer> & bufReqs)88 int ExternalCameraDeviceSession::BufferRequestThread::requestBufferStart(
89         const std::vector<HalStreamBuffer>& bufReqs) {
90     if (bufReqs.empty()) {
91         ALOGE("%s: bufReqs is empty!", __FUNCTION__);
92         return -1;
93     }
94 
95     {
96         std::lock_guard<std::mutex> lk(mLock);
97         if (mRequestingBuffer) {
98             ALOGE("%s: BufferRequestThread does not support more than one concurrent request!",
99                     __FUNCTION__);
100             return -1;
101         }
102 
103         mBufferReqs = bufReqs;
104         mRequestingBuffer = true;
105     }
106     mRequestCond.notify_one();
107     return 0;
108 }
109 
waitForBufferRequestDone(std::vector<HalStreamBuffer> * outBufReq)110 int ExternalCameraDeviceSession::BufferRequestThread::waitForBufferRequestDone(
111         std::vector<HalStreamBuffer>* outBufReq) {
112     std::unique_lock<std::mutex> lk(mLock);
113     if (!mRequestingBuffer) {
114         ALOGE("%s: no pending buffer request!", __FUNCTION__);
115         return -1;
116     }
117 
118     if (mPendingReturnBufferReqs.empty()) {
119         std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqProcTimeoutMs);
120         auto st = mRequestDoneCond.wait_for(lk, timeout);
121         if (st == std::cv_status::timeout) {
122             ALOGE("%s: wait for buffer request finish timeout!", __FUNCTION__);
123             return -1;
124         }
125     }
126     mRequestingBuffer = false;
127     *outBufReq = std::move(mPendingReturnBufferReqs);
128     mPendingReturnBufferReqs.clear();
129     return 0;
130 }
131 
waitForNextRequest()132 void ExternalCameraDeviceSession::BufferRequestThread::waitForNextRequest() {
133     ATRACE_CALL();
134     std::unique_lock<std::mutex> lk(mLock);
135     int waitTimes = 0;
136     while (mBufferReqs.empty()) {
137         if (exitPending()) {
138             return;
139         }
140         std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
141         auto st = mRequestCond.wait_for(lk, timeout);
142         if (st == std::cv_status::timeout) {
143             waitTimes++;
144             if (waitTimes == kReqWaitTimesWarn) {
145                 // BufferRequestThread just wait forever for new buffer request
146                 // But it will print some periodic warning indicating it's waiting
147                 ALOGV("%s: still waiting for new buffer request", __FUNCTION__);
148                 waitTimes = 0;
149             }
150         }
151     }
152 
153     // Fill in hidl BufferRequest
154     mHalBufferReqs.resize(mBufferReqs.size());
155     for (size_t i = 0; i < mHalBufferReqs.size(); i++) {
156         mHalBufferReqs[i].streamId = mBufferReqs[i].streamId;
157         mHalBufferReqs[i].numBuffersRequested = 1;
158     }
159 }
160 
threadLoop()161 bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
162     waitForNextRequest();
163     if (exitPending()) {
164         return false;
165     }
166 
167     ATRACE_BEGIN("HIDL requestStreamBuffers");
168     BufferRequestStatus status;
169     hidl_vec<StreamBufferRet> bufRets;
170     auto err = mCallbacks->requestStreamBuffers(mHalBufferReqs,
171             [&status, &bufRets]
172             (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) {
173                 status = s;
174                 bufRets = std::move(rets);
175             });
176     ATRACE_END();
177     if (!err.isOk()) {
178         ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
179         return false;
180     }
181 
182     std::unique_lock<std::mutex> lk(mLock);
183     if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
184         if (bufRets.size() != mHalBufferReqs.size()) {
185             ALOGE("%s: expect %zu buffer requests returned, only got %zu",
186                     __FUNCTION__, mHalBufferReqs.size(), bufRets.size());
187             return false;
188         }
189 
190         auto parent = mParent.promote();
191         if (parent == nullptr) {
192             ALOGE("%s: session has been disconnected!", __FUNCTION__);
193             return false;
194         }
195 
196         hidl_vec<int> importedFences;
197         importedFences.resize(bufRets.size());
198         for (size_t i = 0; i < bufRets.size(); i++) {
199             int streamId = bufRets[i].streamId;
200             switch (bufRets[i].val.getDiscriminator()) {
201                 case StreamBuffersVal::hidl_discriminator::error:
202                     continue;
203                 case StreamBuffersVal::hidl_discriminator::buffers: {
204                     const hidl_vec<V3_2::StreamBuffer>& hBufs = bufRets[i].val.buffers();
205                     if (hBufs.size() != 1) {
206                         ALOGE("%s: expect 1 buffer returned, got %zu!", __FUNCTION__, hBufs.size());
207                         return false;
208                     }
209                     const V3_2::StreamBuffer& hBuf = hBufs[0];
210 
211                     mBufferReqs[i].bufferId = hBuf.bufferId;
212                     // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
213                     // repeatedly?
214                     lk.unlock();
215                     Status s = parent->importBuffer(streamId,
216                             hBuf.bufferId, hBuf.buffer.getNativeHandle(),
217                             /*out*/&mBufferReqs[i].bufPtr,
218                             /*allowEmptyBuf*/false);
219                     lk.lock();
220 
221                     if (s != Status::OK) {
222                         ALOGE("%s: stream %d import buffer failed!", __FUNCTION__, streamId);
223                         cleanupInflightFences(importedFences, i - 1);
224                         return false;
225                     }
226                     if (!sHandleImporter.importFence(hBuf.acquireFence,
227                             mBufferReqs[i].acquireFence)) {
228                         ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
229                         cleanupInflightFences(importedFences, i - 1);
230                         return false;
231                     }
232                     importedFences[i] = mBufferReqs[i].acquireFence;
233                 }
234                 break;
235                 default:
236                     ALOGE("%s: unkown StreamBuffersVal discrimator!", __FUNCTION__);
237                     return false;
238             }
239         }
240     } else {
241         ALOGE("%s: requestStreamBuffers call failed!", __FUNCTION__);
242     }
243 
244     mPendingReturnBufferReqs = std::move(mBufferReqs);
245     mBufferReqs.clear();
246 
247     lk.unlock();
248     mRequestDoneCond.notify_one();
249     return true;
250 }
251 
initOutputThread()252 void ExternalCameraDeviceSession::initOutputThread() {
253     if (mSupportBufMgr) {
254         mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
255         mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
256     }
257     mOutputThread = new OutputThread(
258             this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
259 }
260 
closeOutputThreadImpl()261 void ExternalCameraDeviceSession::closeOutputThreadImpl() {
262     if (mBufferRequestThread) {
263         mBufferRequestThread->requestExit();
264         mBufferRequestThread->join();
265         mBufferRequestThread.clear();
266     }
267 }
268 
closeOutputThread()269 void ExternalCameraDeviceSession::closeOutputThread() {
270     closeOutputThreadImpl();
271     V3_4::implementation::ExternalCameraDeviceSession::closeOutputThread();
272 }
273 
OutputThread(wp<OutputThreadInterface> parent,CroppingType ct,const common::V1_0::helper::CameraMetadata & chars,sp<BufferRequestThread> bufReqThread)274 ExternalCameraDeviceSession::OutputThread::OutputThread(
275         wp<OutputThreadInterface> parent,
276         CroppingType ct,
277         const common::V1_0::helper::CameraMetadata& chars,
278         sp<BufferRequestThread> bufReqThread) :
279         V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
280         mBufferRequestThread(bufReqThread) {}
281 
~OutputThread()282 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
283 
requestBufferStart(const std::vector<HalStreamBuffer> & bufs)284 int ExternalCameraDeviceSession::OutputThread::requestBufferStart(
285         const std::vector<HalStreamBuffer>& bufs) {
286     if (mBufferRequestThread != nullptr) {
287         return mBufferRequestThread->requestBufferStart(bufs);
288     }
289     return 0;
290 }
291 
waitForBufferRequestDone(std::vector<HalStreamBuffer> * outBufs)292 int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone(
293         /*out*/std::vector<HalStreamBuffer>* outBufs) {
294     if (mBufferRequestThread != nullptr) {
295         return mBufferRequestThread->waitForBufferRequestDone(outBufs);
296     }
297     return 0;
298 }
299 
isReconfigurationRequired(const V3_2::CameraMetadata &,const V3_2::CameraMetadata &,ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb)300 Return<void> ExternalCameraDeviceSession::isReconfigurationRequired(
301         const V3_2::CameraMetadata& /*oldSessionParams*/,
302         const V3_2::CameraMetadata& /*newSessionParams*/,
303         ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) {
304     //Stub implementation
305     _hidl_cb(Status::OK, true);
306     return Void();
307 }
308 
309 } // namespace implementation
310 }  // namespace V3_5
311 }  // namespace device
312 }  // namespace camera
313 }  // namespace hardware
314 }  // namespace android
315