| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | ** | 
|  | 3 | ** Copyright (C) 2013, The Android Open Source Project | 
|  | 4 | ** | 
|  | 5 | ** Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 6 | ** you may not use this file except in compliance with the License. | 
|  | 7 | ** You may obtain a copy of the License at | 
|  | 8 | ** | 
|  | 9 | **     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 10 | ** | 
|  | 11 | ** Unless required by applicable law or agreed to in writing, software | 
|  | 12 | ** distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 14 | ** See the License for the specific language governing permissions and | 
|  | 15 | ** limitations under the License. | 
|  | 16 | */ | 
|  | 17 |  | 
|  | 18 | //#define LOG_NDEBUG 0 | 
|  | 19 | #define LOG_TAG "CameraBase" | 
|  | 20 | #include <utils/Log.h> | 
|  | 21 | #include <utils/threads.h> | 
|  | 22 | #include <utils/Mutex.h> | 
| Ivan Podogov | ee844a8 | 2016-09-15 11:32:41 +0100 | [diff] [blame] | 23 | #include <cutils/properties.h> | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 24 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 25 | #include <android/hardware/ICameraService.h> | 
|  | 26 |  | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 27 | #include <binder/IPCThreadState.h> | 
|  | 28 | #include <binder/IServiceManager.h> | 
|  | 29 | #include <binder/IMemory.h> | 
|  | 30 |  | 
|  | 31 | #include <camera/CameraBase.h> | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 32 |  | 
|  | 33 | // needed to instantiate | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 34 | #include <camera/Camera.h> | 
|  | 35 |  | 
|  | 36 | #include <system/camera_metadata.h> | 
|  | 37 |  | 
|  | 38 | namespace android { | 
|  | 39 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 40 | namespace hardware { | 
|  | 41 |  | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 42 | status_t CameraInfo::writeToParcel(android::Parcel* parcel) const { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 43 | status_t res; | 
|  | 44 | res = parcel->writeInt32(facing); | 
|  | 45 | if (res != OK) return res; | 
|  | 46 | res = parcel->writeInt32(orientation); | 
|  | 47 | return res; | 
|  | 48 | } | 
|  | 49 |  | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 50 | status_t CameraInfo::readFromParcel(const android::Parcel* parcel) { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 51 | status_t res; | 
|  | 52 | res = parcel->readInt32(&facing); | 
|  | 53 | if (res != OK) return res; | 
|  | 54 | res = parcel->readInt32(&orientation); | 
|  | 55 | return res; | 
|  | 56 | } | 
|  | 57 |  | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 58 | status_t CameraStatus::writeToParcel(android::Parcel* parcel) const { | 
| Oleksiy Vyalov | ead8472 | 2017-03-24 14:06:03 -0700 | [diff] [blame] | 59 | auto res = parcel->writeString16(String16(cameraId)); | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 60 | if (res != OK) return res; | 
| Oleksiy Vyalov | ead8472 | 2017-03-24 14:06:03 -0700 | [diff] [blame] | 61 |  | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 62 | res = parcel->writeInt32(status); | 
| Shuzhen Wang | 4385816 | 2020-01-10 13:42:15 -0800 | [diff] [blame] | 63 | if (res != OK) return res; | 
|  | 64 |  | 
|  | 65 | std::vector<String16> unavailablePhysicalIds16; | 
|  | 66 | for (auto& id8 : unavailablePhysicalIds) { | 
|  | 67 | unavailablePhysicalIds16.push_back(String16(id8)); | 
|  | 68 | } | 
|  | 69 | res = parcel->writeString16Vector(unavailablePhysicalIds16); | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 70 | return res; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 71 | } | 
|  | 72 |  | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 73 | status_t CameraStatus::readFromParcel(const android::Parcel* parcel) { | 
| Oleksiy Vyalov | ead8472 | 2017-03-24 14:06:03 -0700 | [diff] [blame] | 74 | String16 tempCameraId; | 
|  | 75 | auto res = parcel->readString16(&tempCameraId); | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 76 | if (res != OK) return res; | 
| Oleksiy Vyalov | ead8472 | 2017-03-24 14:06:03 -0700 | [diff] [blame] | 77 | cameraId = String8(tempCameraId); | 
|  | 78 |  | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 79 | res = parcel->readInt32(&status); | 
| Shuzhen Wang | 4385816 | 2020-01-10 13:42:15 -0800 | [diff] [blame] | 80 | if (res != OK) return res; | 
|  | 81 |  | 
|  | 82 | std::vector<String16> unavailablePhysicalIds16; | 
|  | 83 | res = parcel->readString16Vector(&unavailablePhysicalIds16); | 
|  | 84 | if (res != OK) return res; | 
|  | 85 | for (auto& id16 : unavailablePhysicalIds16) { | 
|  | 86 | unavailablePhysicalIds.push_back(String8(id16)); | 
|  | 87 | } | 
| Eino-Ville Talvala | f51fca2 | 2016-12-13 11:25:55 -0800 | [diff] [blame] | 88 | return res; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | } // namespace hardware | 
|  | 92 |  | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 93 | namespace { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 94 | sp<::android::hardware::ICameraService> gCameraService; | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 95 | const int                 kCameraServicePollDelay = 500000; // 0.5s | 
|  | 96 | const char*               kCameraServiceName      = "media.camera"; | 
|  | 97 |  | 
|  | 98 | Mutex                     gLock; | 
|  | 99 |  | 
|  | 100 | class DeathNotifier : public IBinder::DeathRecipient | 
|  | 101 | { | 
|  | 102 | public: | 
|  | 103 | DeathNotifier() { | 
|  | 104 | } | 
|  | 105 |  | 
| Mark Salyzyn | 7b73e71 | 2014-06-09 16:28:21 -0700 | [diff] [blame] | 106 | virtual void binderDied(const wp<IBinder>& /*who*/) { | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 107 | ALOGV("binderDied"); | 
|  | 108 | Mutex::Autolock _l(gLock); | 
|  | 109 | gCameraService.clear(); | 
|  | 110 | ALOGW("Camera service died!"); | 
|  | 111 | } | 
|  | 112 | }; | 
|  | 113 |  | 
|  | 114 | sp<DeathNotifier>         gDeathNotifier; | 
|  | 115 | }; // namespace anonymous | 
|  | 116 |  | 
|  | 117 | /////////////////////////////////////////////////////////// | 
|  | 118 | // CameraBase definition | 
|  | 119 | /////////////////////////////////////////////////////////// | 
|  | 120 |  | 
|  | 121 | // establish binder interface to camera service | 
|  | 122 | template <typename TCam, typename TCamTraits> | 
| Eino-Ville Talvala | f86177d | 2017-02-01 15:27:41 -0800 | [diff] [blame] | 123 | const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService() | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 124 | { | 
|  | 125 | Mutex::Autolock _l(gLock); | 
|  | 126 | if (gCameraService.get() == 0) { | 
| Ivan Podogov | ee844a8 | 2016-09-15 11:32:41 +0100 | [diff] [blame] | 127 | char value[PROPERTY_VALUE_MAX]; | 
|  | 128 | property_get("config.disable_cameraservice", value, "0"); | 
|  | 129 | if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) { | 
|  | 130 | return gCameraService; | 
|  | 131 | } | 
|  | 132 |  | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 133 | sp<IServiceManager> sm = defaultServiceManager(); | 
|  | 134 | sp<IBinder> binder; | 
|  | 135 | do { | 
|  | 136 | binder = sm->getService(String16(kCameraServiceName)); | 
|  | 137 | if (binder != 0) { | 
|  | 138 | break; | 
|  | 139 | } | 
|  | 140 | ALOGW("CameraService not published, waiting..."); | 
|  | 141 | usleep(kCameraServicePollDelay); | 
|  | 142 | } while(true); | 
|  | 143 | if (gDeathNotifier == NULL) { | 
|  | 144 | gDeathNotifier = new DeathNotifier(); | 
|  | 145 | } | 
|  | 146 | binder->linkToDeath(gDeathNotifier); | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 147 | gCameraService = interface_cast<::android::hardware::ICameraService>(binder); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 148 | } | 
|  | 149 | ALOGE_IF(gCameraService == 0, "no CameraService!?"); | 
|  | 150 | return gCameraService; | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | template <typename TCam, typename TCamTraits> | 
|  | 154 | sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId, | 
| Svetoslav Ganov | 280405a | 2015-05-12 02:19:27 +0000 | [diff] [blame] | 155 | const String16& clientPackageName, | 
| Chien-Yu Chen | 98a668f | 2015-12-18 14:10:33 -0800 | [diff] [blame] | 156 | int clientUid, int clientPid) | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 157 | { | 
|  | 158 | ALOGV("%s: connect", __FUNCTION__); | 
|  | 159 | sp<TCam> c = new TCam(cameraId); | 
|  | 160 | sp<TCamCallbacks> cl = c; | 
| Eino-Ville Talvala | f86177d | 2017-02-01 15:27:41 -0800 | [diff] [blame] | 161 | const sp<::android::hardware::ICameraService> cs = getCameraService(); | 
| Ruben Brunk | 0f61d8f | 2013-08-08 13:07:18 -0700 | [diff] [blame] | 162 |  | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 163 | binder::Status ret; | 
|  | 164 | if (cs != nullptr) { | 
| Ruben Brunk | 0f61d8f | 2013-08-08 13:07:18 -0700 | [diff] [blame] | 165 | TCamConnectService fnConnectService = TCamTraits::fnConnectService; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 166 | ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, | 
|  | 167 | clientPid, /*out*/ &c->mCamera); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 168 | } | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 169 | if (ret.isOk() && c->mCamera != nullptr) { | 
| Marco Nelissen | 06b4606 | 2014-11-14 07:58:25 -0800 | [diff] [blame] | 170 | IInterface::asBinder(c->mCamera)->linkToDeath(c); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 171 | c->mStatus = NO_ERROR; | 
|  | 172 | } else { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 173 | ALOGW("An error occurred while connecting to camera %d: %s", cameraId, | 
| Tobias Lindskog | 0ccb13b | 2016-11-01 14:25:52 +0100 | [diff] [blame] | 174 | (cs == nullptr) ? "Service not available" : ret.toString8().string()); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 175 | c.clear(); | 
|  | 176 | } | 
|  | 177 | return c; | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 | template <typename TCam, typename TCamTraits> | 
|  | 181 | void CameraBase<TCam, TCamTraits>::disconnect() | 
|  | 182 | { | 
|  | 183 | ALOGV("%s: disconnect", __FUNCTION__); | 
|  | 184 | if (mCamera != 0) { | 
|  | 185 | mCamera->disconnect(); | 
| Marco Nelissen | 06b4606 | 2014-11-14 07:58:25 -0800 | [diff] [blame] | 186 | IInterface::asBinder(mCamera)->unlinkToDeath(this); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 187 | mCamera = 0; | 
|  | 188 | } | 
|  | 189 | ALOGV("%s: disconnect (done)", __FUNCTION__); | 
|  | 190 | } | 
|  | 191 |  | 
|  | 192 | template <typename TCam, typename TCamTraits> | 
|  | 193 | CameraBase<TCam, TCamTraits>::CameraBase(int cameraId) : | 
|  | 194 | mStatus(UNKNOWN_ERROR), | 
|  | 195 | mCameraId(cameraId) | 
|  | 196 | { | 
|  | 197 | } | 
|  | 198 |  | 
|  | 199 | template <typename TCam, typename TCamTraits> | 
|  | 200 | CameraBase<TCam, TCamTraits>::~CameraBase() | 
|  | 201 | { | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | template <typename TCam, typename TCamTraits> | 
|  | 205 | sp<typename TCamTraits::TCamUser> CameraBase<TCam, TCamTraits>::remote() | 
|  | 206 | { | 
|  | 207 | return mCamera; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | template <typename TCam, typename TCamTraits> | 
|  | 211 | status_t CameraBase<TCam, TCamTraits>::getStatus() | 
|  | 212 | { | 
|  | 213 | return mStatus; | 
|  | 214 | } | 
|  | 215 |  | 
|  | 216 | template <typename TCam, typename TCamTraits> | 
| Mark Salyzyn | 7b73e71 | 2014-06-09 16:28:21 -0700 | [diff] [blame] | 217 | void CameraBase<TCam, TCamTraits>::binderDied(const wp<IBinder>& /*who*/) { | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 218 | ALOGW("mediaserver's remote binder Camera object died"); | 
|  | 219 | notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, /*ext2*/0); | 
|  | 220 | } | 
|  | 221 |  | 
|  | 222 | template <typename TCam, typename TCamTraits> | 
|  | 223 | void CameraBase<TCam, TCamTraits>::setListener(const sp<TCamListener>& listener) | 
|  | 224 | { | 
|  | 225 | Mutex::Autolock _l(mLock); | 
|  | 226 | mListener = listener; | 
|  | 227 | } | 
|  | 228 |  | 
|  | 229 | // callback from camera service | 
|  | 230 | template <typename TCam, typename TCamTraits> | 
|  | 231 | void CameraBase<TCam, TCamTraits>::notifyCallback(int32_t msgType, | 
|  | 232 | int32_t ext1, | 
|  | 233 | int32_t ext2) | 
|  | 234 | { | 
|  | 235 | sp<TCamListener> listener; | 
|  | 236 | { | 
|  | 237 | Mutex::Autolock _l(mLock); | 
|  | 238 | listener = mListener; | 
|  | 239 | } | 
|  | 240 | if (listener != NULL) { | 
|  | 241 | listener->notify(msgType, ext1, ext2); | 
|  | 242 | } | 
|  | 243 | } | 
|  | 244 |  | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 245 | template <typename TCam, typename TCamTraits> | 
|  | 246 | int CameraBase<TCam, TCamTraits>::getNumberOfCameras() { | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 247 | const sp<::android::hardware::ICameraService> cs = getCameraService(); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 248 |  | 
|  | 249 | if (!cs.get()) { | 
|  | 250 | // as required by the public Java APIs | 
|  | 251 | return 0; | 
|  | 252 | } | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 253 | int32_t count; | 
|  | 254 | binder::Status res = cs->getNumberOfCameras( | 
|  | 255 | ::android::hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE, | 
|  | 256 | &count); | 
|  | 257 | if (!res.isOk()) { | 
|  | 258 | ALOGE("Error reading number of cameras: %s", | 
|  | 259 | res.toString8().string()); | 
|  | 260 | count = 0; | 
|  | 261 | } | 
|  | 262 | return count; | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 263 | } | 
|  | 264 |  | 
|  | 265 | // this can be in BaseCamera but it should be an instance method | 
|  | 266 | template <typename TCam, typename TCamTraits> | 
|  | 267 | status_t CameraBase<TCam, TCamTraits>::getCameraInfo(int cameraId, | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 268 | struct hardware::CameraInfo* cameraInfo) { | 
| Eino-Ville Talvala | f86177d | 2017-02-01 15:27:41 -0800 | [diff] [blame] | 269 | const sp<::android::hardware::ICameraService> cs = getCameraService(); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 270 | if (cs == 0) return UNKNOWN_ERROR; | 
| Eino-Ville Talvala | d56db1d | 2015-12-17 16:50:35 -0800 | [diff] [blame] | 271 | binder::Status res = cs->getCameraInfo(cameraId, cameraInfo); | 
|  | 272 | return res.isOk() ? OK : res.serviceSpecificErrorCode(); | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 273 | } | 
|  | 274 |  | 
| Igor Murashkin | c073ba5 | 2013-02-26 14:32:34 -0800 | [diff] [blame] | 275 | template class CameraBase<Camera>; | 
|  | 276 |  | 
|  | 277 | } // namespace android |