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>
23#include <cutils/properties.h>
24
25#include <android/hardware/ICameraService.h>
26
27#include <binder/IPCThreadState.h>
28#include <binder/IServiceManager.h>
29#include <binder/IMemory.h>
30
31#include <camera/CameraBase.h>
32
33// needed to instantiate
34#include <camera/Camera.h>
35
36#include <system/camera_metadata.h>
37
38namespace android {
39
40namespace hardware {
41
42status_t CameraInfo::writeToParcel(android::Parcel* parcel) const {
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
50status_t CameraInfo::readFromParcel(const android::Parcel* parcel) {
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
58status_t CameraStatus::writeToParcel(android::Parcel* parcel) const {
59    auto res = parcel->writeString16(String16(cameraId));
60    if (res != OK) return res;
61
62    res = parcel->writeInt32(status);
63    return res;
64}
65
66status_t CameraStatus::readFromParcel(const android::Parcel* parcel) {
67    String16 tempCameraId;
68    auto res = parcel->readString16(&tempCameraId);
69    if (res != OK) return res;
70    cameraId = String8(tempCameraId);
71
72    res = parcel->readInt32(&status);
73    return res;
74}
75
76} // namespace hardware
77
78namespace {
79    sp<::android::hardware::ICameraService> gCameraService;
80    const int                 kCameraServicePollDelay = 500000; // 0.5s
81    const char*               kCameraServiceName      = "media.camera";
82
83    Mutex                     gLock;
84
85    class DeathNotifier : public IBinder::DeathRecipient
86    {
87    public:
88        DeathNotifier() {
89        }
90
91        virtual void binderDied(const wp<IBinder>& /*who*/) {
92            ALOGV("binderDied");
93            Mutex::Autolock _l(gLock);
94            gCameraService.clear();
95            ALOGW("Camera service died!");
96        }
97    };
98
99    sp<DeathNotifier>         gDeathNotifier;
100}; // namespace anonymous
101
102///////////////////////////////////////////////////////////
103// CameraBase definition
104///////////////////////////////////////////////////////////
105
106// establish binder interface to camera service
107template <typename TCam, typename TCamTraits>
108const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
109{
110    Mutex::Autolock _l(gLock);
111    if (gCameraService.get() == 0) {
112        char value[PROPERTY_VALUE_MAX];
113        property_get("config.disable_cameraservice", value, "0");
114        if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) {
115            return gCameraService;
116        }
117
118        sp<IServiceManager> sm = defaultServiceManager();
119        sp<IBinder> binder;
120        do {
121            binder = sm->getService(String16(kCameraServiceName));
122            if (binder != 0) {
123                break;
124            }
125            ALOGW("CameraService not published, waiting...");
126            usleep(kCameraServicePollDelay);
127        } while(true);
128        if (gDeathNotifier == NULL) {
129            gDeathNotifier = new DeathNotifier();
130        }
131        binder->linkToDeath(gDeathNotifier);
132        gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
133    }
134    ALOGE_IF(gCameraService == 0, "no CameraService!?");
135    return gCameraService;
136}
137
138template <typename TCam, typename TCamTraits>
139sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
140                                               const String16& clientPackageName,
141                                               int clientUid, int clientPid)
142{
143    ALOGV("%s: connect", __FUNCTION__);
144    sp<TCam> c = new TCam(cameraId);
145    sp<TCamCallbacks> cl = c;
146    const sp<::android::hardware::ICameraService> cs = getCameraService();
147
148    binder::Status ret;
149    if (cs != nullptr) {
150        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
151        ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
152                                               clientPid, /*out*/ &c->mCamera);
153    }
154    if (ret.isOk() && c->mCamera != nullptr) {
155        IInterface::asBinder(c->mCamera)->linkToDeath(c);
156        c->mStatus = NO_ERROR;
157    } else {
158        ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
159                (cs == nullptr) ? "Service not available" : ret.toString8().string());
160        c.clear();
161    }
162    return c;
163}
164
165template <typename TCam, typename TCamTraits>
166void CameraBase<TCam, TCamTraits>::disconnect()
167{
168    ALOGV("%s: disconnect", __FUNCTION__);
169    if (mCamera != 0) {
170        mCamera->disconnect();
171        IInterface::asBinder(mCamera)->unlinkToDeath(this);
172        mCamera = 0;
173    }
174    ALOGV("%s: disconnect (done)", __FUNCTION__);
175}
176
177template <typename TCam, typename TCamTraits>
178CameraBase<TCam, TCamTraits>::CameraBase(int cameraId) :
179    mStatus(UNKNOWN_ERROR),
180    mCameraId(cameraId)
181{
182}
183
184template <typename TCam, typename TCamTraits>
185CameraBase<TCam, TCamTraits>::~CameraBase()
186{
187}
188
189template <typename TCam, typename TCamTraits>
190sp<typename TCamTraits::TCamUser> CameraBase<TCam, TCamTraits>::remote()
191{
192    return mCamera;
193}
194
195template <typename TCam, typename TCamTraits>
196status_t CameraBase<TCam, TCamTraits>::getStatus()
197{
198    return mStatus;
199}
200
201template <typename TCam, typename TCamTraits>
202void CameraBase<TCam, TCamTraits>::binderDied(const wp<IBinder>& /*who*/) {
203    ALOGW("mediaserver's remote binder Camera object died");
204    notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, /*ext2*/0);
205}
206
207template <typename TCam, typename TCamTraits>
208void CameraBase<TCam, TCamTraits>::setListener(const sp<TCamListener>& listener)
209{
210    Mutex::Autolock _l(mLock);
211    mListener = listener;
212}
213
214// callback from camera service
215template <typename TCam, typename TCamTraits>
216void CameraBase<TCam, TCamTraits>::notifyCallback(int32_t msgType,
217                                                  int32_t ext1,
218                                                  int32_t ext2)
219{
220    sp<TCamListener> listener;
221    {
222        Mutex::Autolock _l(mLock);
223        listener = mListener;
224    }
225    if (listener != NULL) {
226        listener->notify(msgType, ext1, ext2);
227    }
228}
229
230template <typename TCam, typename TCamTraits>
231int CameraBase<TCam, TCamTraits>::getNumberOfCameras() {
232    const sp<::android::hardware::ICameraService> cs = getCameraService();
233
234    if (!cs.get()) {
235        // as required by the public Java APIs
236        return 0;
237    }
238    int32_t count;
239    binder::Status res = cs->getNumberOfCameras(
240            ::android::hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
241            &count);
242    if (!res.isOk()) {
243        ALOGE("Error reading number of cameras: %s",
244                res.toString8().string());
245        count = 0;
246    }
247    return count;
248}
249
250// this can be in BaseCamera but it should be an instance method
251template <typename TCam, typename TCamTraits>
252status_t CameraBase<TCam, TCamTraits>::getCameraInfo(int cameraId,
253        struct hardware::CameraInfo* cameraInfo) {
254    const sp<::android::hardware::ICameraService> cs = getCameraService();
255    if (cs == 0) return UNKNOWN_ERROR;
256    binder::Status res = cs->getCameraInfo(cameraId, cameraInfo);
257    return res.isOk() ? OK : res.serviceSpecificErrorCode();
258}
259
260template class CameraBase<Camera>;
261
262} // namespace android
263