1 /*
2  * Copyright 2021 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 #include "EvsServiceContext.h"
18 
19 #include <android-base/logging.h>
20 #include <android/hardware_buffer.h>
21 #include <android_runtime/android_hardware_HardwareBuffer.h>
22 #include <nativehelper/JNIHelp.h>
23 #include <vndk/hardware_buffer.h>
24 
25 using android::hardware::automotive::evs::V1_0::EvsResult;
26 using namespace android::hardware::automotive::evs::V1_1;
27 
28 namespace {
29 
getMethodIDOrDie(JNIEnv * env,jclass clazz,const char * name,const char * signature)30 jmethodID getMethodIDOrDie(JNIEnv* env, jclass clazz, const char* name, const char* signature) {
31     jmethodID res = env->GetMethodID(clazz, name, signature);
32     LOG_ALWAYS_FATAL_IF(res == nullptr, "Unable to find method %s with signature %s", name,
33                         signature);
34 
35     return res;
36 }
37 
38 }  // namespace
39 
40 namespace android {
41 namespace automotive {
42 namespace evs {
43 
44 // "default" is reserved for the latest version of EVS manager.
45 const char* EvsServiceContext::kServiceName = "default";
46 
EvsServiceContext(JavaVM * vm,jclass clazz)47 EvsServiceContext::EvsServiceContext(JavaVM* vm, jclass clazz) :
48       mVm(vm), mCallbackThread(vm), mCarEvsServiceObj(nullptr) {
49     JNIEnv* env = nullptr;
50     vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
51     if (env != nullptr) {
52         // Registers post-native handlers
53         mDeathHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeDeathHandler", "()V");
54         mEventHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeEventHandler", "(I)V");
55         mFrameHandlerMethodId = getMethodIDOrDie(env, clazz, "postNativeFrameHandler",
56                                                  "(ILandroid/hardware/HardwareBuffer;)V");
57     } else {
58         jniThrowException(env, "java/lang/IllegalArgumentException",
59                           "Failed to get JNIEnv from a given VM instance.");
60     }
61 }
62 
~EvsServiceContext()63 EvsServiceContext::~EvsServiceContext() {
64     {
65         std::lock_guard<std::mutex> lock(mLock);
66         if (mService != nullptr) {
67             mService->unlinkToDeath(mDeathRecipient);
68         }
69         mService = nullptr;
70         mCamera = nullptr;
71         mStreamHandler = nullptr;
72     }
73 
74     // Stops the callback thread
75     mCallbackThread.stop();
76 
77     // Deletes a global reference to the CarEvsService object
78     JNIEnv* env = nullptr;
79     if (mVm != nullptr) {
80         mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
81         if (env != nullptr) {
82             env->DeleteGlobalRef(mCarEvsServiceObj);
83         }
84     }
85 }
86 
initialize(JNIEnv * env,jobject thiz)87 bool EvsServiceContext::initialize(JNIEnv* env, jobject thiz) {
88     sp<IEvsEnumerator> service = IEvsEnumerator::tryGetService(EvsServiceContext::kServiceName);
89     if (!service) {
90         // TODO(b/177923058): it may be desired to retry a few times if the
91         // connection fails.
92         LOG(ERROR) << "Failed to connect to EVS service.";
93         return false;
94     }
95 
96     sp<EvsDeathRecipient> deathRecipient = new EvsDeathRecipient(service, this);
97     auto ret = service->linkToDeath(deathRecipient, /*cookie=*/0);
98     if (!ret.isOk() || ret == false) {
99         LOG(ERROR) << "Failed to register a death recipient; the service may die.";
100         return false;
101     }
102 
103     {
104         std::lock_guard<std::mutex> lock(mLock);
105         mService = service;
106         mDeathRecipient = deathRecipient;
107         if (!mCarEvsServiceObj) {
108             mCarEvsServiceObj = env->NewGlobalRef(thiz);
109         }
110     }
111 
112     return true;
113 }
114 
openCamera(const char * id)115 bool EvsServiceContext::openCamera(const char* id) {
116     if (!isAvailable()) {
117         LOG(ERROR) << "Has not connected to EVS service yet.";
118         return false;
119     }
120 
121     if (isCameraOpened()) {
122         if (!strcmp(id, mCameraIdInUse)) {
123             LOG(DEBUG) << "Camera " << id << " is has opened already.";
124             return true;
125         } else {
126             // Close a current camera device.
127             mService->closeCamera(mCamera);
128         }
129     }
130 
131     sp<IEvsCamera> camera = IEvsCamera::castFrom(mService->openCamera(id));
132     if (!camera) {
133         LOG(ERROR) << "Failed to open a camera " << id;
134         return false;
135     }
136 
137     sp<StreamHandler> streamHandler =
138             new StreamHandler(camera, this, EvsServiceContext::kMaxNumFramesInFlight);
139     if (!streamHandler) {
140         LOG(ERROR) << "Failed to initialize a stream streamHandler.";
141         return false;
142     }
143 
144     {
145         std::lock_guard<std::mutex> lock(mLock);
146         mCamera = camera;
147         mStreamHandler = streamHandler;
148         mCameraIdInUse = id;
149     }
150 
151     return true;
152 }
153 
closeCamera()154 void EvsServiceContext::closeCamera() {
155     if (!isCameraOpened()) {
156         LOG(DEBUG) << "Camera has not opened yet.";
157         return;
158     }
159 
160     mService->closeCamera(mCamera);
161 }
162 
startVideoStream()163 bool EvsServiceContext::startVideoStream() {
164     if (!isCameraOpened()) {
165         LOG(ERROR) << "Camera has not opened yet.";
166         return JNI_FALSE;
167     }
168 
169     return mStreamHandler->startStream();
170 }
171 
stopVideoStream()172 void EvsServiceContext::stopVideoStream() {
173     if (!isCameraOpened()) {
174         LOG(DEBUG) << "Camera has not opened; a request to stop a video steram is ignored.";
175         return;
176     }
177 
178     if (!mStreamHandler->asyncStopStream()) {
179         LOG(WARNING) << "Failed to stop a video stream.  EVS service may die.";
180     }
181 }
182 
acquireCameraAndDisplay()183 void EvsServiceContext::acquireCameraAndDisplay() {
184     // Acquires the display ownership.  Because EVS awards this to the single
185     // client, no other clients can use EvsDisplay as long as CarEvsManager
186     // alives.
187     mDisplay = mService->openDisplay_1_1(EvsServiceContext::kExclusiveMainDisplayId);
188     if (!mDisplay) {
189         LOG(WARNING) << "Failed to acquire the display ownership.  "
190                      << "CarEvsManager may not be able to render "
191                      << "the contents on the screen.";
192         return;
193     }
194 
195     // Attempts to become a primary owner
196     auto ret = mCamera->forceMaster(mDisplay);
197     if (!ret.isOk() || ret != EvsResult::OK) {
198         LOG(WARNING) << "Failed to own a camera device.";
199     }
200 }
201 
doneWithFrame(int bufferId)202 void EvsServiceContext::doneWithFrame(int bufferId) {
203     BufferDesc bufferToReturn;
204     {
205         std::lock_guard<std::mutex> lock(mLock);
206         auto it = mBufferRecords.find(bufferId);
207         if (it == mBufferRecords.end()) {
208             LOG(WARNING) << "Unknown buffer is requested to return.";
209             return;
210         }
211 
212         bufferToReturn = it->second;
213         mBufferRecords.erase(it);
214     }
215     mStreamHandler->doneWithFrame(bufferToReturn);
216 
217     // If this is the first frame since current video stream started, we'd claim
218     // the exclusive ownership of the camera and the display and keep for the rest
219     // of the lifespan.
220     std::call_once(mDisplayAcquired, &EvsServiceContext::acquireCameraAndDisplay, this);
221 }
222 
223 /*
224  * Forwards EVS stream events to the client.  This method will run in the
225  * context of EvsCallbackThread.
226  */
onNewEvent(EvsEventDesc event)227 void EvsServiceContext::onNewEvent(EvsEventDesc event) {
228     mCallbackThread.enqueue([event, this](JNIEnv* env) {
229         // Gives an event callback
230         env->CallVoidMethod(mCarEvsServiceObj, mEventHandlerMethodId,
231                             static_cast<jint>(event.aType));
232     });
233 }
234 
235 /*
236  * Forwards EVS frames to the client.  This method will run in the context of
237  * EvsCallbackThread.
238  */
onNewFrame(BufferDesc bufferDesc)239 void EvsServiceContext::onNewFrame(BufferDesc bufferDesc) {
240     mCallbackThread.enqueue([bufferDesc, this](JNIEnv* env) {
241         const auto createFromAHardwareBuffer =
242                 android::android_hardware_HardwareBuffer_createFromAHardwareBuffer;
243 
244         // Clones a AHardwareBuffer
245         AHardwareBuffer_Desc const* desc =
246                 reinterpret_cast<AHardwareBuffer_Desc const*>(&bufferDesc.buffer.description);
247 
248         AHardwareBuffer* rawBuffer;
249         auto status =
250                 AHardwareBuffer_createFromHandle(desc, bufferDesc.buffer.nativeHandle,
251                                                  AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
252                                                  &rawBuffer);
253         if (status != android::NO_ERROR) {
254             LOG(ERROR) << "Failed to create a raw hardware buffer from a native handle.";
255             mStreamHandler->doneWithFrame(bufferDesc);
256         } else {
257             {
258                 std::lock_guard<std::mutex> lock(mLock);
259                 mBufferRecords.try_emplace(bufferDesc.bufferId, bufferDesc);
260             }
261 
262             // Calls back
263             jobject hwBuffer = createFromAHardwareBuffer(env, rawBuffer);
264             if (!hwBuffer) {
265                 LOG(WARNING) << "Failed to create HardwareBuffer from AHardwareBuffer.";
266                 mStreamHandler->doneWithFrame(bufferDesc);
267             } else {
268                 env->CallVoidMethod(mCarEvsServiceObj, mFrameHandlerMethodId, bufferDesc.bufferId,
269                                     hwBuffer);
270             }
271             env->DeleteLocalRef(hwBuffer);
272             AHardwareBuffer_release(rawBuffer);
273         }
274     });
275 }
276 
277 /*
278  * Handles an unexpected death of EVS service.  This method will run in the
279  * context of EvsCallbackThread.
280  */
onServiceDied(const wp<hidl::base::V1_0::IBase> & who)281 void EvsServiceContext::onServiceDied(const wp<hidl::base::V1_0::IBase>& who) {
282     mCallbackThread.enqueue([who, this](JNIEnv* env) {
283         if (!isEqual(who)) {
284             // We're not interested in this death notification.
285             return;
286         }
287 
288         // Drops invalidated service handles.  We will re-initialize them when
289         // we try to reconnect.  The buffer record would be cleared safely
290         // because all buffer references get invalidated upon the death of the
291         // native EVS service.
292         {
293             std::lock_guard<std::mutex> lock(mLock);
294             mCamera = nullptr;
295             mService = nullptr;
296             mStreamHandler = nullptr;
297             mBufferRecords.clear();
298         }
299 
300         LOG(ERROR) << "The native EVS service has died.";
301         // EVS service has died but CarEvsManager instance still alives.
302         // Only a service handle needs to be destroyed; this will be
303         // re-created when CarEvsManager successfully connects to EVS service
304         // when it comes back.
305         env->CallVoidMethod(mCarEvsServiceObj, mDeathHandlerMethodId);
306     });
307 }
308 
309 }  // namespace evs
310 }  // namespace automotive
311 }  // namespace android
312