blob: fc3f137984b9c0c15bfa7a526f7289c9cf5ba0ac [file] [log] [blame]
Emilian Peevb2bc5a42019-11-20 16:02:14 -08001/*
Emilian Peevd99c8ae2019-11-26 13:19:13 -08002 * Copyright (C) 2019 The Android Open Source Project
Emilian Peevb2bc5a42019-11-20 16:02:14 -08003 *
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 "CameraOfflineClient"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21#include "CameraOfflineSessionClient.h"
Emilian Peevd99c8ae2019-11-26 13:19:13 -080022#include "utils/CameraThreadState.h"
Emilian Peevb2bc5a42019-11-20 16:02:14 -080023#include <utils/Trace.h>
24
25namespace android {
26
27using binder::Status;
28
29status_t CameraOfflineSessionClient::initialize(sp<CameraProviderManager>, const String8&) {
Emilian Peevd99c8ae2019-11-26 13:19:13 -080030 ATRACE_CALL();
31
32 // Verify ops permissions
33 auto res = startCameraOps();
34 if (res != OK) {
35 return res;
36 }
37
38 if (mOfflineSession.get() == nullptr) {
39 ALOGE("%s: Camera %s: No valid offline session",
40 __FUNCTION__, mCameraIdStr.string());
41 return NO_INIT;
42 }
43
44 wp<NotificationListener> weakThis(this);
45 res = mOfflineSession->initialize(weakThis);
46 if (res != OK) {
47 ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
48 __FUNCTION__, mCameraIdStr.string(), strerror(-res), res);
49 return res;
50 }
51
Emilian Peevb2bc5a42019-11-20 16:02:14 -080052 return OK;
53}
54
Eino-Ville Talvalaf2e37092020-01-07 15:32:32 -080055status_t CameraOfflineSessionClient::setRotateAndCropOverride(uint8_t /*rotateAndCrop*/) {
56 // Since we're not submitting more capture requests, changes to rotateAndCrop override
57 // make no difference.
58 return OK;
59}
60
Emilian Peevd99c8ae2019-11-26 13:19:13 -080061status_t CameraOfflineSessionClient::dump(int fd, const Vector<String16>& args) {
62 return BasicClient::dump(fd, args);
Emilian Peevb2bc5a42019-11-20 16:02:14 -080063}
64
Emilian Peevd99c8ae2019-11-26 13:19:13 -080065status_t CameraOfflineSessionClient::dumpClient(int fd, const Vector<String16>& /*args*/) {
66 String8 result;
67
68 result = " Offline session dump:\n";
69 write(fd, result.string(), result.size());
70
71 if (mOfflineSession.get() == nullptr) {
72 result = " *** Offline session is detached\n";
73 write(fd, result.string(), result.size());
74 return NO_ERROR;
75 }
76
77 auto res = mOfflineSession->dump(fd);
78 if (res != OK) {
79 result = String8::format(" Error dumping offline session: %s (%d)",
80 strerror(-res), res);
81 write(fd, result.string(), result.size());
82 }
83
Emilian Peevb2bc5a42019-11-20 16:02:14 -080084 return OK;
85}
86
87binder::Status CameraOfflineSessionClient::disconnect() {
Emilian Peevd99c8ae2019-11-26 13:19:13 -080088 Mutex::Autolock icl(mBinderSerializationLock);
89
Emilian Peevb2bc5a42019-11-20 16:02:14 -080090 binder::Status res = Status::ok();
91 if (mDisconnected) {
92 return res;
93 }
Emilian Peevd99c8ae2019-11-26 13:19:13 -080094 // Allow both client and the media server to disconnect at all times
95 int callingPid = CameraThreadState::getCallingPid();
96 if (callingPid != mClientPid &&
97 callingPid != mServicePid) {
98 return res;
99 }
100
Emilian Peevb2bc5a42019-11-20 16:02:14 -0800101 mDisconnected = true;
102
103 sCameraService->removeByClient(this);
104 sCameraService->logDisconnectedOffline(mCameraIdStr, mClientPid, String8(mClientPackageName));
105
106 sp<IBinder> remote = getRemote();
107 if (remote != nullptr) {
108 remote->unlinkToDeath(sCameraService);
109 }
110
111 finishCameraOps();
112 ALOGI("%s: Disconnected client for offline camera %s for PID %d", __FUNCTION__,
113 mCameraIdStr.string(), mClientPid);
114
115 // client shouldn't be able to call into us anymore
116 mClientPid = 0;
117
Emilian Peevd99c8ae2019-11-26 13:19:13 -0800118 if (mOfflineSession.get() != nullptr) {
119 auto ret = mOfflineSession->disconnect();
120 if (ret != OK) {
121 ALOGE("%s: Failed disconnecting from offline session %s (%d)", __FUNCTION__,
122 strerror(-ret), ret);
123 }
124 mOfflineSession = nullptr;
125 }
126
Emilian Peev4697b642019-11-19 17:11:14 -0800127 for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
128 auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
129 if (ret != OK) {
130 ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
131 strerror(-ret), ret);
132 }
133 }
134 mCompositeStreamMap.clear();
135
Emilian Peevb2bc5a42019-11-20 16:02:14 -0800136 return res;
137}
138
139void CameraOfflineSessionClient::notifyError(int32_t errorCode,
140 const CaptureResultExtras& resultExtras) {
141 // Thread safe. Don't bother locking.
Emilian Peev4697b642019-11-19 17:11:14 -0800142 // Composites can have multiple internal streams. Error notifications coming from such internal
143 // streams may need to remain within camera service.
144 bool skipClientNotification = false;
145 for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
146 skipClientNotification |= mCompositeStreamMap.valueAt(i)->onError(errorCode, resultExtras);
147 }
148
Emilian Peevd99c8ae2019-11-26 13:19:13 -0800149 if ((mRemoteCallback.get() != nullptr) && (!skipClientNotification)) {
150 mRemoteCallback->onDeviceError(errorCode, resultExtras);
Emilian Peevb2bc5a42019-11-20 16:02:14 -0800151 }
152}
153
154status_t CameraOfflineSessionClient::startCameraOps() {
155 ATRACE_CALL();
156 {
157 ALOGV("%s: Start camera ops, package name = %s, client UID = %d",
158 __FUNCTION__, String8(mClientPackageName).string(), mClientUid);
159 }
160
161 if (mAppOpsManager != nullptr) {
162 // Notify app ops that the camera is not available
163 mOpsCallback = new OpsCallback(this);
164 int32_t res;
165 // TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
166 mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
167 mClientPackageName, mOpsCallback);
168 // TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
169 res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA,
170 mClientUid, mClientPackageName, /*startIfModeDefault*/ false);
171
172 if (res == AppOpsManager::MODE_ERRORED) {
173 ALOGI("Offline Camera %s: Access for \"%s\" has been revoked",
174 mCameraIdStr.string(), String8(mClientPackageName).string());
175 return PERMISSION_DENIED;
176 }
177
178 if (res == AppOpsManager::MODE_IGNORED) {
179 ALOGI("Offline Camera %s: Access for \"%s\" has been restricted",
180 mCameraIdStr.string(), String8(mClientPackageName).string());
181 // Return the same error as for device policy manager rejection
182 return -EACCES;
183 }
184 }
185
186 mOpsActive = true;
187
188 // Transition device state to OPEN
189 sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
190
191 return OK;
192}
193
194status_t CameraOfflineSessionClient::finishCameraOps() {
195 ATRACE_CALL();
196
197 // Check if startCameraOps succeeded, and if so, finish the camera op
198 if (mOpsActive) {
199 // Notify app ops that the camera is available again
200 if (mAppOpsManager != nullptr) {
201 // TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
202 mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
203 mClientPackageName);
204 mOpsActive = false;
205 }
206 }
207 // Always stop watching, even if no camera op is active
208 if (mOpsCallback != nullptr && mAppOpsManager != nullptr) {
209 mAppOpsManager->stopWatchingMode(mOpsCallback);
210 }
211 mOpsCallback.clear();
212
213 sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
214
215 return OK;
216}
217
Emilian Peev4697b642019-11-19 17:11:14 -0800218void CameraOfflineSessionClient::onResultAvailable(const CaptureResult& result) {
219 ATRACE_CALL();
220 ALOGV("%s", __FUNCTION__);
221
Emilian Peevd99c8ae2019-11-26 13:19:13 -0800222 if (mRemoteCallback.get() != NULL) {
223 mRemoteCallback->onResultReceived(result.mMetadata, result.mResultExtras,
Emilian Peev4697b642019-11-19 17:11:14 -0800224 result.mPhysicalMetadatas);
225 }
226
227 for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
228 mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
229 }
230}
231
232void CameraOfflineSessionClient::notifyShutter(const CaptureResultExtras& resultExtras,
233 nsecs_t timestamp) {
Emilian Peevd99c8ae2019-11-26 13:19:13 -0800234
235 if (mRemoteCallback.get() != nullptr) {
236 mRemoteCallback->onCaptureStarted(resultExtras, timestamp);
Emilian Peev4697b642019-11-19 17:11:14 -0800237 }
238
239 for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
240 mCompositeStreamMap.valueAt(i)->onShutter(resultExtras, timestamp);
241 }
242}
243
Emilian Peevd99c8ae2019-11-26 13:19:13 -0800244void CameraOfflineSessionClient::notifyIdle() {
245 if (mRemoteCallback.get() != nullptr) {
246 mRemoteCallback->onDeviceIdle();
247 }
248}
249
250void CameraOfflineSessionClient::notifyAutoFocus(uint8_t newState, int triggerId) {
251 (void)newState;
252 (void)triggerId;
253
254 ALOGV("%s: Autofocus state now %d, last trigger %d",
255 __FUNCTION__, newState, triggerId);
256}
257
258void CameraOfflineSessionClient::notifyAutoExposure(uint8_t newState, int triggerId) {
259 (void)newState;
260 (void)triggerId;
261
262 ALOGV("%s: Autoexposure state now %d, last trigger %d",
263 __FUNCTION__, newState, triggerId);
264}
265
266void CameraOfflineSessionClient::notifyAutoWhitebalance(uint8_t newState, int triggerId) {
267 (void)newState;
268 (void)triggerId;
269
270 ALOGV("%s: Auto-whitebalance state now %d, last trigger %d", __FUNCTION__, newState,
271 triggerId);
272}
273
274void CameraOfflineSessionClient::notifyPrepared(int /*streamId*/) {
275 ALOGE("%s: Unexpected stream prepare notification in offline mode!", __FUNCTION__);
276 notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
277 CaptureResultExtras());
278}
279
280void CameraOfflineSessionClient::notifyRequestQueueEmpty() {
281 if (mRemoteCallback.get() != nullptr) {
282 mRemoteCallback->onRequestQueueEmpty();
283 }
284}
285
286void CameraOfflineSessionClient::notifyRepeatingRequestError(long /*lastFrameNumber*/) {
287 ALOGE("%s: Unexpected repeating request error in offline mode!", __FUNCTION__);
288 notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
289 CaptureResultExtras());
290}
291
Emilian Peevb2bc5a42019-11-20 16:02:14 -0800292// ----------------------------------------------------------------------------
293}; // namespace android