/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera2ClientBase" #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include #include "common/Camera2ClientBase.h" #include "api2/CameraDeviceClient.h" #include "device3/Camera3Device.h" #include "device3/aidl/AidlCamera3Device.h" #include "device3/hidl/HidlCamera3Device.h" #include "utils/CameraThreadState.h" #include "utils/CameraServiceProxyWrapper.h" namespace android { using namespace camera2; // Interface used by CameraService template Camera2ClientBase::Camera2ClientBase( const sp& cameraService, const sp& remoteCallback, const String16& clientPackageName, bool systemNativeClient, const std::optional& clientFeatureId, const String8& cameraId, int api1CameraId, int cameraFacing, int sensorOrientation, int clientPid, uid_t clientUid, int servicePid, bool overrideForPerfClass, bool overrideToPortrait, bool legacyClient): TClientBase(cameraService, remoteCallback, clientPackageName, systemNativeClient, clientFeatureId, cameraId, api1CameraId, cameraFacing, sensorOrientation, clientPid, clientUid, servicePid, overrideToPortrait), mSharedCameraCallbacks(remoteCallback), mDeviceActive(false), mApi1CameraId(api1CameraId) { ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(), String8(clientPackageName).string(), clientPid, clientUid); mInitialClientPid = clientPid; mOverrideForPerfClass = overrideForPerfClass; mLegacyClient = legacyClient; } template status_t Camera2ClientBase::checkPid(const char* checkLocation) const { int callingPid = CameraThreadState::getCallingPid(); if (callingPid == TClientBase::mClientPid) return NO_ERROR; ALOGE("%s: attempt to use a locked camera from a different process" " (old pid %d, new pid %d)", checkLocation, TClientBase::mClientPid, callingPid); return PERMISSION_DENIED; } template status_t Camera2ClientBase::initialize(sp manager, const String8& monitorTags) { return initializeImpl(manager, monitorTags); } template template status_t Camera2ClientBase::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) { ATRACE_CALL(); ALOGV("%s: Initializing client for camera %s", __FUNCTION__, TClientBase::mCameraIdStr.string()); status_t res; // Verify ops permissions res = TClientBase::startCameraOps(); if (res != OK) { return res; } IPCTransport providerTransport = IPCTransport::INVALID; res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr.string(), &providerTransport); if (res != OK) { return res; } switch (providerTransport) { case IPCTransport::HIDL: mDevice = new HidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass, TClientBase::mOverrideToPortrait, mLegacyClient); break; case IPCTransport::AIDL: mDevice = new AidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass, TClientBase::mOverrideToPortrait, mLegacyClient); break; default: ALOGE("%s Invalid transport for camera id %s", __FUNCTION__, TClientBase::mCameraIdStr.string()); return NO_INIT; } if (mDevice == NULL) { ALOGE("%s: Camera %s: No device connected", __FUNCTION__, TClientBase::mCameraIdStr.string()); return NO_INIT; } res = mDevice->initialize(providerPtr, monitorTags); if (res != OK) { ALOGE("%s: Camera %s: unable to initialize device: %s (%d)", __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res); return res; } wp weakThis(this); res = mDevice->setNotifyCallback(weakThis); /** Start watchdog thread */ mCameraServiceWatchdog = new CameraServiceWatchdog(); mCameraServiceWatchdog->run("Camera2ClientBaseWatchdog"); return OK; } template Camera2ClientBase::~Camera2ClientBase() { ATRACE_CALL(); TClientBase::mDestructionStarted = true; disconnect(); if (mCameraServiceWatchdog != NULL) { mCameraServiceWatchdog->requestExit(); mCameraServiceWatchdog.clear(); } ALOGI("Closed Camera %s. Client was: %s (PID %d, UID %u)", TClientBase::mCameraIdStr.string(), String8(TClientBase::mClientPackageName).string(), mInitialClientPid, TClientBase::mClientUid); } template status_t Camera2ClientBase::dumpClient(int fd, const Vector& args) { String8 result; result.appendFormat("Camera2ClientBase[%s] (%p) PID: %d, dump:\n", TClientBase::mCameraIdStr.string(), (TClientBase::getRemoteCallback() != NULL ? IInterface::asBinder(TClientBase::getRemoteCallback()).get() : NULL), TClientBase::mClientPid); result.append(" State: "); write(fd, result.string(), result.size()); // TODO: print dynamic/request section from most recent requests return dumpDevice(fd, args); } template status_t Camera2ClientBase::startWatchingTags(const String8 &tags, int out) { sp device = mDevice; if (!device) { dprintf(out, " Device is detached"); return OK; } return device->startWatchingTags(tags); } template status_t Camera2ClientBase::stopWatchingTags(int out) { sp device = mDevice; if (!device) { dprintf(out, " Device is detached"); return OK; } return device->stopWatchingTags(); } template status_t Camera2ClientBase::dumpWatchedEventsToVector(std::vector &out) { sp device = mDevice; if (!device) { // Nothing to dump if the device is detached return OK; } return device->dumpWatchedEventsToVector(out); } template status_t Camera2ClientBase::dumpDevice( int fd, const Vector& args) { String8 result; result = " Device dump:\n"; write(fd, result.string(), result.size()); sp device = mDevice; if (!device.get()) { result = " *** Device is detached\n"; write(fd, result.string(), result.size()); return NO_ERROR; } status_t res = device->dump(fd, args); if (res != OK) { result = String8::format(" Error dumping device: %s (%d)", strerror(-res), res); write(fd, result.string(), result.size()); } return NO_ERROR; } // ICameraClient2BaseUser interface template binder::Status Camera2ClientBase::disconnect() { if (mCameraServiceWatchdog != nullptr && mDevice != nullptr) { // Timer for the disconnect call should be greater than getExpectedInFlightDuration // since this duration is used to error handle methods in the disconnect sequence // thus allowing existing error handling methods to execute first uint64_t maxExpectedDuration = ns2ms(mDevice->getExpectedInFlightDuration() + kBufferTimeDisconnectNs); // Initialization from hal succeeded, time disconnect. return mCameraServiceWatchdog->WATCH_CUSTOM_TIMER(disconnectImpl(), maxExpectedDuration / kCycleLengthMs, kCycleLengthMs); } return disconnectImpl(); } template binder::Status Camera2ClientBase::disconnectImpl() { ATRACE_CALL(); ALOGD("Camera %s: start to disconnect", TClientBase::mCameraIdStr.string()); Mutex::Autolock icl(mBinderSerializationLock); ALOGD("Camera %s: serializationLock acquired", TClientBase::mCameraIdStr.string()); binder::Status res = binder::Status::ok(); // Allow both client and the media server to disconnect at all times int callingPid = CameraThreadState::getCallingPid(); if (callingPid != TClientBase::mClientPid && callingPid != TClientBase::mServicePid) return res; ALOGD("Camera %s: Shutting down", TClientBase::mCameraIdStr.string()); // Before detaching the device, cache the info from current open session. // The disconnected check avoids duplication of info and also prevents // deadlock while acquiring service lock in cacheDump. if (!TClientBase::mDisconnected) { ALOGD("Camera %s: start to cacheDump", TClientBase::mCameraIdStr.string()); Camera2ClientBase::getCameraService()->cacheDump(); } detachDevice(); CameraService::BasicClient::disconnect(); ALOGV("Camera %s: Shut down complete", TClientBase::mCameraIdStr.string()); return res; } template void Camera2ClientBase::detachDevice() { if (mDevice == 0) return; mDevice->disconnect(); ALOGV("Camera %s: Detach complete", TClientBase::mCameraIdStr.string()); } template status_t Camera2ClientBase::connect( const sp& client) { ATRACE_CALL(); ALOGV("%s: E", __FUNCTION__); Mutex::Autolock icl(mBinderSerializationLock); if (TClientBase::mClientPid != 0 && CameraThreadState::getCallingPid() != TClientBase::mClientPid) { ALOGE("%s: Camera %s: Connection attempt from pid %d; " "current locked to pid %d", __FUNCTION__, TClientBase::mCameraIdStr.string(), CameraThreadState::getCallingPid(), TClientBase::mClientPid); return BAD_VALUE; } TClientBase::mClientPid = CameraThreadState::getCallingPid(); TClientBase::mRemoteCallback = client; mSharedCameraCallbacks = client; return OK; } /** Device-related methods */ template void Camera2ClientBase::notifyError( int32_t errorCode, const CaptureResultExtras& resultExtras) { ALOGE("Error condition %d reported by HAL, requestId %" PRId32, errorCode, resultExtras.requestId); } template void Camera2ClientBase::notifyPhysicalCameraChange(const std::string &physicalId) { // We're only interested in this notification if overrideToPortrait is turned on. if (!TClientBase::mOverrideToPortrait) { return; } String8 physicalId8(physicalId.c_str()); auto physicalCameraMetadata = mDevice->infoPhysical(physicalId8); auto orientationEntry = physicalCameraMetadata.find(ANDROID_SENSOR_ORIENTATION); if (orientationEntry.count == 1) { int orientation = orientationEntry.data.i32[0]; int rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_NONE; if (orientation == 0 || orientation == 180) { rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90; } static_cast(this)->setRotateAndCropOverride(rotateAndCropMode); } } template status_t Camera2ClientBase::notifyActive(float maxPreviewFps) { if (!mDeviceActive) { status_t res = TClientBase::startCameraStreamingOps(); if (res != OK) { ALOGE("%s: Camera %s: Error starting camera streaming ops: %d", __FUNCTION__, TClientBase::mCameraIdStr.string(), res); return res; } CameraServiceProxyWrapper::logActive(TClientBase::mCameraIdStr, maxPreviewFps); } mDeviceActive = true; ALOGV("Camera device is now active"); return OK; } template void Camera2ClientBase::notifyIdleWithUserTag( int64_t requestCount, int64_t resultErrorCount, bool deviceError, const std::vector& streamStats, const std::string& userTag, int videoStabilizationMode) { if (mDeviceActive) { status_t res = TClientBase::finishCameraStreamingOps(); if (res != OK) { ALOGE("%s: Camera %s: Error finishing streaming ops: %d", __FUNCTION__, TClientBase::mCameraIdStr.string(), res); } CameraServiceProxyWrapper::logIdle(TClientBase::mCameraIdStr, requestCount, resultErrorCount, deviceError, userTag, videoStabilizationMode, streamStats); } mDeviceActive = false; ALOGV("Camera device is now idle"); } template void Camera2ClientBase::notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) { (void)resultExtras; (void)timestamp; ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, __FUNCTION__, resultExtras.requestId, timestamp); } template void Camera2ClientBase::notifyAutoFocus(uint8_t newState, int triggerId) { (void)newState; (void)triggerId; ALOGV("%s: Autofocus state now %d, last trigger %d", __FUNCTION__, newState, triggerId); } template void Camera2ClientBase::notifyAutoExposure(uint8_t newState, int triggerId) { (void)newState; (void)triggerId; ALOGV("%s: Autoexposure state now %d, last trigger %d", __FUNCTION__, newState, triggerId); } template void Camera2ClientBase::notifyAutoWhitebalance(uint8_t newState, int triggerId) { (void)newState; (void)triggerId; ALOGV("%s: Auto-whitebalance state now %d, last trigger %d", __FUNCTION__, newState, triggerId); } template void Camera2ClientBase::notifyPrepared(int streamId) { (void)streamId; ALOGV("%s: Stream %d now prepared", __FUNCTION__, streamId); } template void Camera2ClientBase::notifyRequestQueueEmpty() { ALOGV("%s: Request queue now empty", __FUNCTION__); } template void Camera2ClientBase::notifyRepeatingRequestError(long lastFrameNumber) { (void)lastFrameNumber; ALOGV("%s: Repeating request was stopped. Last frame number is %ld", __FUNCTION__, lastFrameNumber); } template int Camera2ClientBase::getCameraId() const { return mApi1CameraId; } template const sp& Camera2ClientBase::getCameraDevice() { return mDevice; } template const sp& Camera2ClientBase::getCameraService() { return TClientBase::sCameraService; } template Camera2ClientBase::SharedCameraCallbacks::Lock::Lock( SharedCameraCallbacks &client) : mRemoteCallback(client.mRemoteCallback), mSharedClient(client) { mSharedClient.mRemoteCallbackLock.lock(); } template Camera2ClientBase::SharedCameraCallbacks::Lock::~Lock() { mSharedClient.mRemoteCallbackLock.unlock(); } template Camera2ClientBase::SharedCameraCallbacks::SharedCameraCallbacks( const sp&client) : mRemoteCallback(client) { } template typename Camera2ClientBase::SharedCameraCallbacks& Camera2ClientBase::SharedCameraCallbacks::operator=( const sp&client) { Mutex::Autolock l(mRemoteCallbackLock); mRemoteCallback = client; return *this; } template void Camera2ClientBase::SharedCameraCallbacks::clear() { Mutex::Autolock l(mRemoteCallbackLock); mRemoteCallback.clear(); } template status_t Camera2ClientBase::injectCamera(const String8& injectedCamId, sp manager) { return mDevice->injectCamera(injectedCamId, manager); } template status_t Camera2ClientBase::stopInjection() { return mDevice->stopInjection(); } template class Camera2ClientBase; template class Camera2ClientBase; } // namespace android