本来想用这一篇博客把cameraHAL的实现和流程都给写完的.搞了半天,东西实在是太多了.这篇先写cameraHAL的基本实现框架,下一篇在具体写camerahal的流程吧.

cameraHAL的实现:

对于初学者来说,最大的疑问是系统是如何调用hardware的.
这里就以camera来举例说明.
调用hardware的程序是cameraservice,我们就去它里面看看它是如何找到hardware的

先把源码贴上来:

/*
**
** Copyright (C) 2008, 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 "CameraService"
//#define LOG_NDEBUG 0 #include <stdio.h>
#include <sys/types.h>
#include <pthread.h> #include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <gui/SurfaceTextureClient.h>
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
#include <media/mediaplayer.h>
#include <surfaceflinger/ISurface.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h> #include "CameraService.h"
#include "CameraHardwareInterface.h" namespace android { // ----------------------------------------------------------------------------
// Logging support -- this is for debugging only
// Use "adb shell dumpsys media.camera -v 1" to change it.
static volatile int32_t gLogLevel = ; #define LOG1(...) LOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define LOG2(...) LOGD_IF(gLogLevel >= 2, __VA_ARGS__); static void setLogLevel(int level) {
android_atomic_write(level, &gLogLevel);
} // ---------------------------------------------------------------------------- static int getCallingPid() {
return IPCThreadState::self()->getCallingPid();
} static int getCallingUid() {
return IPCThreadState::self()->getCallingUid();
} // ---------------------------------------------------------------------------- // This is ugly and only safe if we never re-create the CameraService, but
// should be ok for now.
static CameraService *gCameraService; CameraService::CameraService()
:mSoundRef(), mModule()
{
LOGI("CameraService started (pid=%d)", getpid());
gCameraService = this;
} void CameraService::onFirstRef()
{
BnCameraService::onFirstRef(); if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule) < ) {
LOGE("Could not load camera HAL module");
mNumberOfCameras = ;
}
else {
mNumberOfCameras = mModule->get_number_of_cameras();
if (mNumberOfCameras > MAX_CAMERAS) {
LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
for (int i = ; i < mNumberOfCameras; i++) {
setCameraFree(i);
}
} // Read the system property to determine if we have to use the
// AUDIO_STREAM_ENFORCED_AUDIBLE type.
char value[PROPERTY_VALUE_MAX];
property_get("ro.camera.sound.forced", value, "");
if (strcmp(value, "") != ) {
mAudioStreamType = AUDIO_STREAM_ENFORCED_AUDIBLE;
} else {
mAudioStreamType = AUDIO_STREAM_MUSIC;
}
} CameraService::~CameraService() {
for (int i = ; i < mNumberOfCameras; i++) {
if (mBusy[i]) {
LOGE("camera %d is still in use in destructor!", i);
}
} gCameraService = NULL;
} int32_t CameraService::getNumberOfCameras() {
return mNumberOfCameras;
} status_t CameraService::getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo) {
if (!mModule) {
return NO_INIT;
} if (cameraId < || cameraId >= mNumberOfCameras) {
return BAD_VALUE;
} struct camera_info info;
status_t rc = mModule->get_camera_info(cameraId, &info);
cameraInfo->facing = info.facing;
cameraInfo->orientation = info.orientation;
return rc;
} sp<ICamera> CameraService::connect(
const sp<ICameraClient>& cameraClient, int cameraId) {
int callingPid = getCallingPid();
sp<CameraHardwareInterface> hardware = NULL; LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId); if (!mModule) {
LOGE("Camera HAL module not loaded");
return NULL;
} sp<Client> client;
if (cameraId < || cameraId >= mNumberOfCameras) {
LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
callingPid, cameraId);
return NULL;
} char value[PROPERTY_VALUE_MAX];
property_get("sys.secpolicy.camera.disabled", value, "");
if (strcmp(value, "") == ) {
// Camera is disabled by DevicePolicyManager.
LOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
return NULL;
} Mutex::Autolock lock(mServiceLock);
if (mClient[cameraId] != ) {
client = mClient[cameraId].promote();
if (client != ) {
if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
LOG1("CameraService::connect X (pid %d) (the same client)",
callingPid);
return client;
} else {
LOGW("CameraService::connect X (pid %d) rejected (existing client).",
callingPid);
return NULL;
}
}
mClient[cameraId].clear();
} if (mBusy[cameraId]) {
LOGW("CameraService::connect X (pid %d) rejected"
" (camera %d is still busy).", callingPid, cameraId);
return NULL;
} struct camera_info info;
if (mModule->get_camera_info(cameraId, &info) != OK) {
LOGE("Invalid camera id %d", cameraId);
return NULL;
} char camera_device_name[];
snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId); hardware = new CameraHardwareInterface(camera_device_name);
if (hardware->initialize(&mModule->common) != OK) {
hardware.clear();
return NULL;
} client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
mClient[cameraId] = client;
LOG1("CameraService::connect X");
return client;
} void CameraService::removeClient(const sp<ICameraClient>& cameraClient) {
int callingPid = getCallingPid();
LOG1("CameraService::removeClient E (pid %d)", callingPid); for (int i = ; i < mNumberOfCameras; i++) {
// Declare this before the lock to make absolutely sure the
// destructor won't be called with the lock held.
sp<Client> client; Mutex::Autolock lock(mServiceLock); // This happens when we have already disconnected (or this is
// just another unused camera).
if (mClient[i] == ) continue; // Promote mClient. It can fail if we are called from this path:
// Client::~Client() -> disconnect() -> removeClient().
client = mClient[i].promote(); if (client == ) {
mClient[i].clear();
continue;
} if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
// Found our camera, clear and leave.
LOG1("removeClient: clear camera %d", i);
mClient[i].clear();
break;
}
} LOG1("CameraService::removeClient X (pid %d)", callingPid);
} sp<CameraService::Client> CameraService::getClientById(int cameraId) {
if (cameraId < || cameraId >= mNumberOfCameras) return NULL;
return mClient[cameraId].promote();
} status_t CameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
// Permission checks
switch (code) {
case BnCameraService::CONNECT:
const int pid = getCallingPid();
const int self_pid = getpid();
if (pid != self_pid) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.CAMERA"))) {
const int uid = getCallingUid();
LOGE("Permission Denial: "
"can't use the camera pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
}
break;
} return BnCameraService::onTransact(code, data, reply, flags);
} // The reason we need this busy bit is a new CameraService::connect() request
// may come in while the previous Client's destructor has not been run or is
// still running. If the last strong reference of the previous Client is gone
// but the destructor has not been finished, we should not allow the new Client
// to be created because we need to wait for the previous Client to tear down
// the hardware first.
void CameraService::setCameraBusy(int cameraId) {
android_atomic_write(, &mBusy[cameraId]);
} void CameraService::setCameraFree(int cameraId) {
android_atomic_write(, &mBusy[cameraId]);
} // We share the media players for shutter and recording sound for all clients.
// A reference count is kept to determine when we will actually release the
// media players. MediaPlayer* CameraService::newMediaPlayer(const char *file) {
MediaPlayer* mp = new MediaPlayer();
if (mp->setDataSource(file, NULL) == NO_ERROR) {
mp->setAudioStreamType(mAudioStreamType);
mp->prepare();
} else {
LOGE("Failed to load CameraService sounds: %s", file);
return NULL;
}
return mp;
} void CameraService::loadSound() {
Mutex::Autolock lock(mSoundLock);
LOG1("CameraService::loadSound ref=%d", mSoundRef);
if (mSoundRef++) return; mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
} void CameraService::releaseSound() {
Mutex::Autolock lock(mSoundLock);
LOG1("CameraService::releaseSound ref=%d", mSoundRef);
if (--mSoundRef) return; for (int i = ; i < NUM_SOUNDS; i++) {
if (mSoundPlayer[i] != ) {
mSoundPlayer[i]->disconnect();
mSoundPlayer[i].clear();
}
}
} void CameraService::playSound(sound_kind kind) {
LOG1("playSound(%d)", kind);
Mutex::Autolock lock(mSoundLock);
sp<MediaPlayer> player = mSoundPlayer[kind];
if (player != ) {
player->seekTo();
player->start();
}
} // ---------------------------------------------------------------------------- CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
const sp<CameraHardwareInterface>& hardware,
int cameraId, int cameraFacing, int clientPid) {
int callingPid = getCallingPid();
LOG1("Client::Client E (pid %d)", callingPid); mCameraService = cameraService;
mCameraClient = cameraClient;
mHardware = hardware;
mCameraId = cameraId;
mCameraFacing = cameraFacing;
mClientPid = clientPid;
mMsgEnabled = ;
mSurface = ;
mPreviewWindow = ;
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)cameraId); // Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA); // Callback is disabled by default
mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(, mCameraFacing == CAMERA_FACING_FRONT);
mPlayShutterSound = true;
cameraService->setCameraBusy(cameraId);
cameraService->loadSound();
LOG1("Client::Client X (pid %d)", callingPid);
} // tear down the client
CameraService::Client::~Client() {
int callingPid = getCallingPid();
LOG1("Client::~Client E (pid %d, this %p)", callingPid, this); // set mClientPid to let disconnet() tear down the hardware
mClientPid = callingPid;
disconnect();
mCameraService->releaseSound();
LOG1("Client::~Client X (pid %d, this %p)", callingPid, this);
} // ---------------------------------------------------------------------------- status_t CameraService::Client::checkPid() const {
int callingPid = getCallingPid();
if (callingPid == mClientPid) return NO_ERROR; LOGW("attempt to use a locked camera from a different process"
" (old pid %d, new pid %d)", mClientPid, callingPid);
return EBUSY;
} status_t CameraService::Client::checkPidAndHardware() const {
status_t result = checkPid();
if (result != NO_ERROR) return result;
if (mHardware == ) {
LOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
return INVALID_OPERATION;
}
return NO_ERROR;
} status_t CameraService::Client::lock() {
int callingPid = getCallingPid();
LOG1("lock (pid %d)", callingPid);
Mutex::Autolock lock(mLock); // lock camera to this client if the the camera is unlocked
if (mClientPid == ) {
mClientPid = callingPid;
return NO_ERROR;
} // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
return checkPid();
} status_t CameraService::Client::unlock() {
int callingPid = getCallingPid();
LOG1("unlock (pid %d)", callingPid);
Mutex::Autolock lock(mLock); // allow anyone to use camera (after they lock the camera)
status_t result = checkPid();
if (result == NO_ERROR) {
if (mHardware->recordingEnabled()) {
LOGE("Not allowed to unlock camera during recording.");
return INVALID_OPERATION;
}
mClientPid = ;
LOG1("clear mCameraClient (pid %d)", callingPid);
// we need to remove the reference to ICameraClient so that when the app
// goes away, the reference count goes to 0.
mCameraClient.clear();
}
return result;
} // connect a new client to the camera
status_t CameraService::Client::connect(const sp<ICameraClient>& client) {
int callingPid = getCallingPid();
LOG1("connect E (pid %d)", callingPid);
Mutex::Autolock lock(mLock); if (mClientPid != && checkPid() != NO_ERROR) {
LOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
mClientPid, callingPid);
return EBUSY;
} if (mCameraClient != && (client->asBinder() == mCameraClient->asBinder())) {
LOG1("Connect to the same client");
return NO_ERROR;
} mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mClientPid = callingPid;
mCameraClient = client; LOG1("connect X (pid %d)", callingPid);
return NO_ERROR;
} static void disconnectWindow(const sp<ANativeWindow>& window) {
if (window != ) {
status_t result = native_window_api_disconnect(window.get(),
NATIVE_WINDOW_API_CAMERA);
if (result != NO_ERROR) {
LOGW("native_window_api_disconnect failed: %s (%d)", strerror(-result),
result);
}
}
} void CameraService::Client::disconnect() {
int callingPid = getCallingPid();
LOG1("disconnect E (pid %d)", callingPid);
Mutex::Autolock lock(mLock); if (checkPid() != NO_ERROR) {
LOGW("different client - don't disconnect");
return;
} if (mClientPid <= ) {
LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
return;
} // Make sure disconnect() is done once and once only, whether it is called
// from the user directly, or called by the destructor.
if (mHardware == ) return; LOG1("hardware teardown");
// Before destroying mHardware, we must make sure it's in the
// idle state.
// Turn off all messages.
disableMsgType(CAMERA_MSG_ALL_MSGS);
mHardware->stopPreview();
mHardware->cancelPicture();
// Release the hardware resources.
mHardware->release(); // Release the held ANativeWindow resources.
if (mPreviewWindow != ) {
disconnectWindow(mPreviewWindow);
mPreviewWindow = ;
mHardware->setPreviewWindow(mPreviewWindow);
}
mHardware.clear(); mCameraService->removeClient(mCameraClient);
mCameraService->setCameraFree(mCameraId); LOG1("disconnect X (pid %d)", callingPid);
} // ---------------------------------------------------------------------------- status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder,
const sp<ANativeWindow>& window) {
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; // return if no change in surface.
if (binder == mSurface) {
return NO_ERROR;
} if (window != ) {
result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
if (result != NO_ERROR) {
LOGE("native_window_api_connect failed: %s (%d)", strerror(-result),
result);
return result;
}
} // If preview has been already started, register preview buffers now.
if (mHardware->previewEnabled()) {
if (window != ) {
native_window_set_scaling_mode(window.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
native_window_set_buffers_transform(window.get(), mOrientation);
result = mHardware->setPreviewWindow(window);
}
} if (result == NO_ERROR) {
// Everything has succeeded. Disconnect the old window and remember the
// new window.
disconnectWindow(mPreviewWindow);
mSurface = binder;
mPreviewWindow = window;
} else {
// Something went wrong after we connected to the new window, so
// disconnect here.
disconnectWindow(window);
} return result;
} // set the Surface that the preview will use
status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid()); sp<IBinder> binder(surface != ? surface->asBinder() : );
sp<ANativeWindow> window(surface);
return setPreviewWindow(binder, window);
} // set the SurfaceTexture that the preview will use
status_t CameraService::Client::setPreviewTexture(
const sp<ISurfaceTexture>& surfaceTexture) {
LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
getCallingPid()); sp<IBinder> binder;
sp<ANativeWindow> window;
if (surfaceTexture != ) {
binder = surfaceTexture->asBinder();
window = new SurfaceTextureClient(surfaceTexture);
}
return setPreviewWindow(binder, window);
} // set the preview callback flag to affect how the received frames from
// preview are handled.
void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return; mPreviewCallbackFlag = callback_flag;
if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
} else {
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
}
} // start preview mode
status_t CameraService::Client::startPreview() {
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
} // start recording mode
status_t CameraService::Client::startRecording() {
LOG1("startRecording (pid %d)", getCallingPid());
return startCameraMode(CAMERA_RECORDING_MODE);
} // start preview or recording
status_t CameraService::Client::startCameraMode(camera_mode mode) {
LOG1("startCameraMode(%d)", mode);
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; switch(mode) {
case CAMERA_PREVIEW_MODE:
if (mSurface == && mPreviewWindow == ) {
LOG1("mSurface is not set yet.");
// still able to start preview in this case.
}
return startPreviewMode();
case CAMERA_RECORDING_MODE:
if (mSurface == && mPreviewWindow == ) {
LOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
return INVALID_OPERATION;
}
return startRecordingMode();
default:
return UNKNOWN_ERROR;
}
} status_t CameraService::Client::startPreviewMode() {
LOG1("startPreviewMode");
status_t result = NO_ERROR; // if preview has been enabled, nothing needs to be done
if (mHardware->previewEnabled()) {
return NO_ERROR;
} if (mPreviewWindow != ) {
native_window_set_scaling_mode(mPreviewWindow.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
native_window_set_buffers_transform(mPreviewWindow.get(),
mOrientation);
}
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview(); return result;
} status_t CameraService::Client::startRecordingMode() {
LOG1("startRecordingMode");
status_t result = NO_ERROR; // if recording has been enabled, nothing needs to be done
if (mHardware->recordingEnabled()) {
return NO_ERROR;
} // if preview has not been started, start preview first
if (!mHardware->previewEnabled()) {
result = startPreviewMode();
if (result != NO_ERROR) {
return result;
}
} // start recording mode
enableMsgType(CAMERA_MSG_VIDEO_FRAME);
mCameraService->playSound(SOUND_RECORDING);
result = mHardware->startRecording();
if (result != NO_ERROR) {
LOGE("mHardware->startRecording() failed with status %d", result);
}
return result;
} // stop preview mode
void CameraService::Client::stopPreview() {
LOG1("stopPreview (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return; disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
mHardware->stopPreview(); mPreviewBuffer.clear();
} // stop recording mode
void CameraService::Client::stopRecording() {
LOG1("stopRecording (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return; mCameraService->playSound(SOUND_RECORDING);
disableMsgType(CAMERA_MSG_VIDEO_FRAME);
mHardware->stopRecording(); mPreviewBuffer.clear();
} // release a recording frame
void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
mHardware->releaseRecordingFrame(mem);
} status_t CameraService::Client::storeMetaDataInBuffers(bool enabled)
{
LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) {
return UNKNOWN_ERROR;
}
return mHardware->storeMetaDataInBuffers(enabled);
} bool CameraService::Client::previewEnabled() {
LOG1("previewEnabled (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return false;
return mHardware->previewEnabled();
} bool CameraService::Client::recordingEnabled() {
LOG1("recordingEnabled (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return false;
return mHardware->recordingEnabled();
} status_t CameraService::Client::autoFocus() {
LOG1("autoFocus (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; return mHardware->autoFocus();
} status_t CameraService::Client::cancelAutoFocus() {
LOG1("cancelAutoFocus (pid %d)", getCallingPid()); Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; return mHardware->cancelAutoFocus();
} // take a picture - image is returned in callback
status_t CameraService::Client::takePicture(int msgType) {
LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType); Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
(msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
" cannot be both enabled");
return BAD_VALUE;
} // We only accept picture related message types
// and ignore other types of messages for takePicture().
int picMsgType = msgType
& (CAMERA_MSG_SHUTTER |
CAMERA_MSG_POSTVIEW_FRAME |
CAMERA_MSG_RAW_IMAGE |
CAMERA_MSG_RAW_IMAGE_NOTIFY |
CAMERA_MSG_COMPRESSED_IMAGE); enableMsgType(picMsgType); return mHardware->takePicture();
} // set preview/capture parameters - key/value pairs
status_t CameraService::Client::setParameters(const String8& params) {
LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string()); Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; CameraParameters p(params);
return mHardware->setParameters(p);
} // get preview/capture parameters - key/value pairs
String8 CameraService::Client::getParameters() const {
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return String8(); String8 params(mHardware->getParameters().flatten());
LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
return params;
} // enable shutter sound
status_t CameraService::Client::enableShutterSound(bool enable) {
LOG1("enableShutterSound (pid %d)", getCallingPid()); status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; if (enable) {
mPlayShutterSound = true;
return OK;
} // Disabling shutter sound may not be allowed. In that case only
// allow the mediaserver process to disable the sound.
char value[PROPERTY_VALUE_MAX];
property_get("ro.camera.sound.forced", value, "");
if (strcmp(value, "") != ) {
// Disabling shutter sound is not allowed. Deny if the current
// process is not mediaserver.
if (getCallingPid() != getpid()) {
LOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
return PERMISSION_DENIED;
}
} mPlayShutterSound = false;
return OK;
} status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
LOG1("sendCommand (pid %d)", getCallingPid());
int orientation;
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result; if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
// Mirror the preview if the camera is front-facing.
orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
if (orientation == -) return BAD_VALUE; if (mOrientation != orientation) {
mOrientation = orientation;
if (mPreviewWindow != ) {
native_window_set_buffers_transform(mPreviewWindow.get(),
mOrientation);
}
}
return OK;
} else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
switch (arg1) {
case :
enableShutterSound(false);
break;
case :
enableShutterSound(true);
break;
default:
return BAD_VALUE;
}
return OK;
} else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
mCameraService->playSound(SOUND_RECORDING);
} return mHardware->sendCommand(cmd, arg1, arg2);
} // ---------------------------------------------------------------------------- void CameraService::Client::enableMsgType(int32_t msgType) {
android_atomic_or(msgType, &mMsgEnabled);
mHardware->enableMsgType(msgType);
} void CameraService::Client::disableMsgType(int32_t msgType) {
android_atomic_and(~msgType, &mMsgEnabled);
mHardware->disableMsgType(msgType);
} #define CHECK_MESSAGE_INTERVAL 10 // 10ms
bool CameraService::Client::lockIfMessageWanted(int32_t msgType) {
int sleepCount = ;
while (mMsgEnabled & msgType) {
if (mLock.tryLock() == NO_ERROR) {
if (sleepCount > ) {
LOG1("lockIfMessageWanted(%d): waited for %d ms",
msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
}
return true;
}
if (sleepCount++ == ) {
LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
}
usleep(CHECK_MESSAGE_INTERVAL * );
}
LOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
return false;
} // ---------------------------------------------------------------------------- // Converts from a raw pointer to the client to a strong pointer during a
// hardware callback. This requires the callbacks only happen when the client
// is still alive.
sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) {
sp<Client> client = gCameraService->getClientById((int) user); // This could happen if the Client is in the process of shutting down (the
// last strong reference is gone, but the destructor hasn't finished
// stopping the hardware).
if (client == ) return NULL; // The checks below are not necessary and are for debugging only.
if (client->mCameraService.get() != gCameraService) {
LOGE("mismatch service!");
return NULL;
} if (client->mHardware == ) {
LOGE("mHardware == 0: callback after disconnect()?");
return NULL;
} return client;
} // Callback messages can be dispatched to internal handlers or pass to our
// client's callback functions, depending on the message type.
//
// notifyCallback:
// CAMERA_MSG_SHUTTER handleShutter
// (others) c->notifyCallback
// dataCallback:
// CAMERA_MSG_PREVIEW_FRAME handlePreviewData
// CAMERA_MSG_POSTVIEW_FRAME handlePostview
// CAMERA_MSG_RAW_IMAGE handleRawPicture
// CAMERA_MSG_COMPRESSED_IMAGE handleCompressedPicture
// (others) c->dataCallback
// dataCallbackTimestamp
// (others) c->dataCallbackTimestamp
//
// NOTE: the *Callback functions grab mLock of the client before passing
// control to handle* functions. So the handle* functions must release the
// lock before calling the ICameraClient's callbacks, so those callbacks can
// invoke methods in the Client class again (For example, the preview frame
// callback may want to releaseRecordingFrame). The handle* functions must
// release the lock after all accesses to member variables, so it must be
// handled very carefully. void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1,
int32_t ext2, void* user) {
LOG2("notifyCallback(%d)", msgType); sp<Client> client = getClientFromCookie(user);
if (client == ) return;
if (!client->lockIfMessageWanted(msgType)) return; switch (msgType) {
case CAMERA_MSG_SHUTTER:
// ext1 is the dimension of the yuv picture.
client->handleShutter();
break;
default:
client->handleGenericNotify(msgType, ext1, ext2);
break;
}
} void CameraService::Client::dataCallback(int32_t msgType,
const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
LOG2("dataCallback(%d)", msgType); sp<Client> client = getClientFromCookie(user);
if (client == ) return;
if (!client->lockIfMessageWanted(msgType)) return; if (dataPtr == && metadata == NULL) {
LOGE("Null data returned in data callback");
client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, );
return;
} switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
case CAMERA_MSG_PREVIEW_FRAME:
client->handlePreviewData(msgType, dataPtr, metadata);
break;
case CAMERA_MSG_POSTVIEW_FRAME:
client->handlePostview(dataPtr);
break;
case CAMERA_MSG_RAW_IMAGE:
client->handleRawPicture(dataPtr);
break;
case CAMERA_MSG_COMPRESSED_IMAGE:
client->handleCompressedPicture(dataPtr);
break;
default:
client->handleGenericData(msgType, dataPtr, metadata);
break;
}
} void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
LOG2("dataCallbackTimestamp(%d)", msgType); sp<Client> client = getClientFromCookie(user);
if (client == ) return;
if (!client->lockIfMessageWanted(msgType)) return; if (dataPtr == ) {
LOGE("Null data returned in data with timestamp callback");
client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, );
return;
} client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
} // snapshot taken callback
void CameraService::Client::handleShutter(void) {
if (mPlayShutterSound) {
mCameraService->playSound(SOUND_SHUTTER);
} sp<ICameraClient> c = mCameraClient;
if (c != ) {
mLock.unlock();
c->notifyCallback(CAMERA_MSG_SHUTTER, , );
if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
}
disableMsgType(CAMERA_MSG_SHUTTER); mLock.unlock();
} // preview callback - frame buffer update
void CameraService::Client::handlePreviewData(int32_t msgType,
const sp<IMemory>& mem,
camera_frame_metadata_t *metadata) {
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); // local copy of the callback flags
int flags = mPreviewCallbackFlag; // is callback enabled?
if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
// If the enable bit is off, the copy-out and one-shot bits are ignored
LOG2("frame callback is disabled");
mLock.unlock();
return;
} // hold a strong pointer to the client
sp<ICameraClient> c = mCameraClient; // clear callback flags if no client or one-shot mode
if (c == || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
LOG2("Disable preview callback");
mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
} if (c != ) {
// Is the received frame copied out or not?
if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
LOG2("frame is copied");
copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
} else {
LOG2("frame is forwarded");
mLock.unlock();
c->dataCallback(msgType, mem, metadata);
}
} else {
mLock.unlock();
}
} // picture callback - postview image ready
void CameraService::Client::handlePostview(const sp<IMemory>& mem) {
disableMsgType(CAMERA_MSG_POSTVIEW_FRAME); sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != ) {
c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
}
} // picture callback - raw image ready
void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
disableMsgType(CAMERA_MSG_RAW_IMAGE); ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != ) {
c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
}
} // picture callback - compressed picture ready
void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) {
disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE); sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != ) {
c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
}
} void CameraService::Client::handleGenericNotify(int32_t msgType,
int32_t ext1, int32_t ext2) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != ) {
c->notifyCallback(msgType, ext1, ext2);
}
} void CameraService::Client::handleGenericData(int32_t msgType,
const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != ) {
c->dataCallback(msgType, dataPtr, metadata);
}
} void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,
int32_t msgType, const sp<IMemory>& dataPtr) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != ) {
c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
}
} void CameraService::Client::copyFrameAndPostCopiedFrame(
int32_t msgType, const sp<ICameraClient>& client,
const sp<IMemoryHeap>& heap, size_t offset, size_t size,
camera_frame_metadata_t *metadata) {
LOG2("copyFrameAndPostCopiedFrame");
// It is necessary to copy out of pmem before sending this to
// the callback. For efficiency, reuse the same MemoryHeapBase
// provided it's big enough. Don't allocate the memory or
// perform the copy if there's no callback.
// hold the preview lock while we grab a reference to the preview buffer
sp<MemoryHeapBase> previewBuffer; if (mPreviewBuffer == ) {
mPreviewBuffer = new MemoryHeapBase(size, , NULL);
} else if (size > mPreviewBuffer->virtualSize()) {
mPreviewBuffer.clear();
mPreviewBuffer = new MemoryHeapBase(size, , NULL);
}
if (mPreviewBuffer == ) {
LOGE("failed to allocate space for preview buffer");
mLock.unlock();
return;
}
previewBuffer = mPreviewBuffer; memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size); sp<MemoryBase> frame = new MemoryBase(previewBuffer, , size);
if (frame == ) {
LOGE("failed to allocate space for frame callback");
mLock.unlock();
return;
} mLock.unlock();
client->dataCallback(msgType, frame, metadata);
} int CameraService::Client::getOrientation(int degrees, bool mirror) {
if (!mirror) {
if (degrees == ) return ;
else if (degrees == ) return HAL_TRANSFORM_ROT_90;
else if (degrees == ) return HAL_TRANSFORM_ROT_180;
else if (degrees == ) return HAL_TRANSFORM_ROT_270;
} else { // Do mirror (horizontal flip)
if (degrees == ) { // FLIP_H and ROT_0
return HAL_TRANSFORM_FLIP_H;
} else if (degrees == ) { // FLIP_H and ROT_90
return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
} else if (degrees == ) { // FLIP_H and ROT_180
return HAL_TRANSFORM_FLIP_V;
} else if (degrees == ) { // FLIP_H and ROT_270
return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
}
}
LOGE("Invalid setDisplayOrientation degrees=%d", degrees);
return -;
} // ---------------------------------------------------------------------------- static const int kDumpLockRetries = ;
static const int kDumpLockSleep = ; static bool tryLock(Mutex& mutex)
{
bool locked = false;
for (int i = ; i < kDumpLockRetries; ++i) {
if (mutex.tryLock() == NO_ERROR) {
locked = true;
break;
}
usleep(kDumpLockSleep);
}
return locked;
} status_t CameraService::dump(int fd, const Vector<String16>& args) {
static const char* kDeadlockedString = "CameraService may be deadlocked\n"; const size_t SIZE = ;
char buffer[SIZE];
String8 result;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
snprintf(buffer, SIZE, "Permission Denial: "
"can't dump CameraService from pid=%d, uid=%d\n",
getCallingPid(),
getCallingUid());
result.append(buffer);
write(fd, result.string(), result.size());
} else {
bool locked = tryLock(mServiceLock);
// failed to lock - CameraService is probably deadlocked
if (!locked) {
String8 result(kDeadlockedString);
write(fd, result.string(), result.size());
} bool hasClient = false;
for (int i = ; i < mNumberOfCameras; i++) {
sp<Client> client = mClient[i].promote();
if (client == ) continue;
hasClient = true;
sprintf(buffer, "Client[%d] (%p) PID: %d\n",
i,
client->getCameraClient()->asBinder().get(),
client->mClientPid);
result.append(buffer);
write(fd, result.string(), result.size());
client->mHardware->dump(fd, args);
}
if (!hasClient) {
result.append("No camera client yet.\n");
write(fd, result.string(), result.size());
} if (locked) mServiceLock.unlock(); // change logging level
int n = args.size();
for (int i = ; i + < n; i++) {
if (args[i] == String16("-v")) {
String8 levelStr(args[i+]);
int level = atoi(levelStr.string());
sprintf(buffer, "Set Log Level to %d", level);
result.append(buffer);
setLogLevel(level);
}
}
}
return NO_ERROR;
} }; // namespace android

void CameraService::onFirstRef()看这个函数:

void CameraService::onFirstRef()
{
BnCameraService::onFirstRef(); if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule) < ) {
LOGE("Could not load camera HAL module");
mNumberOfCameras = ;
}
else {
mNumberOfCameras = mModule->get_number_of_cameras(); //获取camera设备的个数.对应下文中的获取camera个数函数.
if (mNumberOfCameras > MAX_CAMERAS) {
LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
for (int i = ; i < mNumberOfCameras; i++) {
setCameraFree(i);
}
} // Read the system property to determine if we have to use the
// AUDIO_STREAM_ENFORCED_AUDIBLE type.
char value[PROPERTY_VALUE_MAX];
property_get("ro.camera.sound.forced", value, "");
if (strcmp(value, "") != ) {
mAudioStreamType = AUDIO_STREAM_ENFORCED_AUDIBLE;
} else {
mAudioStreamType = AUDIO_STREAM_MUSIC;
}
}

找了半天也就是它这个函数里边有hw_get_module()这个函数,一看名字就知道是获取hardware的,不找它找谁啊。那么onFirstRef()函数又是何时调用的?
onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数时调用,什么意思?就是当 有sp包装的类初始化的时候调用。这里在frameworks/base/services/camera/libcameraservice/CameraService.h 中class CameraService :中有定义

  // these are initialized in the constructor.
sp<CameraService> mCameraService; // immutable after constructor
sp<ICameraClient> mCameraClient;
int mCameraId; // immutable after constructor
int mCameraFacing; // immutable after constructor
pid_t mClientPid;
sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
int mPreviewCallbackFlag;
int mOrientation; // Current display orientation
bool mPlayShutterSound;

很明显是这里来初始化的,当然这里不是重点,如果全部都写的话,那基本上就写不完了.

找到了hw_get_module()这个函数,让我们看它的具体实现.
hardware/libhardware/hardware.c
代码如下:

/*
* Copyright (C) 2008 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.
*/ #include <hardware/hardware.h> #include <cutils/properties.h> #include <dlfcn.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <limits.h> #define LOG_TAG "HAL"
#include <utils/Log.h> /** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw" /**
* There are a set of variant filename for modules. The form of the filename
* is "<MODULE_ID>.variant.so" so for the led module the Dream variants
* of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
*
* led.trout.so
* led.msm7k.so
* led.ARMV6.so
* led.default.so
*/ static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
}; static const int HAL_VARIANT_KEYS_COUNT =
(sizeof(variant_keys)/sizeof(variant_keys[])); /**
* Load the file defined by the variant and if successful
* return the dlopen handle and the hmi.
* @return 0 = success, !0 = failure.
*/
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
{
int status;
void *handle;
struct hw_module_t *hmi; /*
* load the symbols resolving undefined symbols before
* dlopen returns. Since RTLD_GLOBAL is not or'd in with
* RTLD_NOW the external symbols will not be global
*/
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
char const *err_str = dlerror();
LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
} /* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
if (hmi == NULL) {
LOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
} /* Check that the id matches */
if (strcmp(id, hmi->id) != ) {
LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
status = -EINVAL;
goto done;
} hmi->dso = handle; /* success */
status = ; done:
if (status != ) {
hmi = NULL;
if (handle != NULL) {
dlclose(handle);
handle = NULL;
}
} else {
LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
id, path, *pHmi, handle);
} *pHmi = hmi; return status;
} int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
int status;
int i;
const struct hw_module_t *hmi = NULL;
char prop[PATH_MAX];
char path[PATH_MAX];
char name[PATH_MAX]; if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
else
strlcpy(name, class_id, PATH_MAX); /*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new copy of the library).
* We also assume that dlopen() is thread-safe.
*/ /* Loop through the configuration variants looking for a module */
for (i= ; i<HAL_VARIANT_KEYS_COUNT+ ; i++) {
if (i < HAL_VARIANT_KEYS_COUNT) {
if (property_get(variant_keys[i], prop, NULL) == ) {
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, prop);
if (access(path, R_OK) == ) break; snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, prop);
if (access(path, R_OK) == ) break;
} else {
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH1, name);
if (access(path, R_OK) == ) break;
}
} status = -ENOENT;
if (i < HAL_VARIANT_KEYS_COUNT+) {
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
status = load(class_id, path, module);
} return status;
} int hw_get_module(const char *id, const struct hw_module_t **module)
{
return hw_get_module_by_class(id, NULL, module);
}

让我们看看它的流程:

int hw_get_module(const char *id, const struct hw_module_t **module)
int hw_get_module_by_class(const char *class_id, const char *inst,const struct hw_module_t **module)
static int load(const char *id,const char *path,const struct hw_module_t **pHmi)
/* Check that the id matches */
if (strcmp(id, hmi->id) != ) {
LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
status = -EINVAL;
goto done;
}
...

可以知道,真正来寻找hardware的桥梁是这个ID,在if (strcmp(id, hmi->id) != 0)中,id是frameworks/base/services/camera/libcameraservice/CameraService.cpp中直接赋值的
如下:

  if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule) < ) {
LOGE("Could not load camera HAL module");
mNumberOfCameras = ;
}

而hmi->id中的这个id很明显是hardware中应该定义的了.
我们看hmi是怎么得来的.

    /* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);

不用跟踪这个函数就能看出来.hmi一定是从sym中来获取的.所以这里我们也就知道hardware中一定要有这个结构体.这也是实现一个hardware必须要做的事情,这里在hardware.h中也有说明:

/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/

即hardware中一定要有这个叫HAL_MODULE_INFO_SYM的结构体.这也是实现一个hardware的第一步:Step-1:实现一个名字为HAL_MODULE_INFO_SYM的结构体,这个结构体必须以hw_module_t开头

好吧,来看一下camera的hardware中是怎么定义的.

看一下common是不是结构体hw_module_t
hardware/libhardware/include/hardware/camera.h

好了,既然hardware要有结构体,那么必须要给他初始化.自定义的函数也得给实现了.
上文注释已经写出来了.这里只是粘贴一下函数的实现.

所以也就自然而然的调用到了实现hardware的第二步,Step-2:
open函数的实现及作用.还是看cameraHAL中对其的实现.

层层包装啊,再看HAL_camera_device_open:

static int HAL_camera_device_open(const struct hw_module_t* module,
const char *id,
struct hw_device_t** device)
{
int cameraId = atoi(id);
if (cameraId < || cameraId >= HAL_getNumberOfCameras()) {
return -EINVAL;
}
if (g_cam_device) { //如果系统第二次打开摄像头,则此时g_cam_device已经填充完毕,可以不再填充了.
if (obj(g_cam_device)->getCameraId() == cameraId) {
goto done;
} else {
LOGE("Cannot open camera %d. camera %d is already running!",
cameraId, obj(g_cam_device)->getCameraId());
return -ENOSYS;
}
}
g_cam_device = (camera_device_t *)malloc(sizeof(camera_device_t));
if (!g_cam_device)
return -ENOMEM;
g_cam_device->common.tag = HARDWARE_DEVICE_TAG;
g_cam_device->common.version = ;
g_cam_device->common.module = const_cast<hw_module_t *>(module);
g_cam_device->common.close = HAL_camera_device_close;
g_cam_device->ops = &camera_device_ops;
LOGI("%s: open camera %s", __func__, id);
g_cam_device->priv = new CameraHardwareSec(cameraId, g_cam_device);
done:
*device = (hw_device_t *)g_cam_device;
LOGI("%s: opened camera %s (%p)", __func__, id, *device);
return ;
}

这里我们知道.open的作用就是打开指定ID号的摄像头以及填充device结构体,供上层直接调用我们HAL的具体函数比如takePicture(),startPreview()等等.
但是应该怎么去填充这个结构体呢?
还是先看hardware/libhardware/include/hardware/hardware.h怎么说吧.

/**
* Every device data structure must begin with hw_device_t
* followed by module specific public methods and attributes.
*/

它说每一个设备都必须以hw_device_t开始,后面跟着methods和attributes.

那我们就在HAL中定义一个static的结构体,按着上边赋值完毕后返回这个指针就成了.看HAL

static camera_device_t *g_cam_device;            //定义设备的结构体具体如下.
typedef struct camera_device {
hw_device_t common; //以hw_device_t开始
camera_device_ops_t *ops; //紧跟着methods
void *priv; //私有数据.
} camera_device_t;

看看是怎么填充的:

g_cam_device->common.tag     = HARDWARE_DEVICE_TAG;        //hardware.h中定义的.具体设备tag必须这样定义.
g_cam_device->common.module = const_cast<hw_module_t *>(module); //和module模块建立联系
g_cam_device->common.close = HAL_camera_device_close; //设备关闭的函数
g_cam_device->ops = &camera_device_ops; // 这个里边包含的就是那些操作摄像头所需要的具体实现.讲HAL的运行流程时细讲.
g_cam_device->priv = new CameraHardwareSec(cameraId, g_cam_device); //真正实现hardware初始化摄像头的函数,讲HAL的运行流程时细讲.

这里先看看camera_device_ops的具体实现,也牵扯到了HAL实现的第三步,Step-3:具体设备的函数实现.

#define SET_METHOD(m) m : HAL_camera_device_##m        //相当于m : HAL_camera_device_m
static camera_device_ops_t camera_device_ops = {
SET_METHOD(set_preview_window), //展开后相当于set_preview_window : HAL_camera_device_set_preview_window,即HAL_camera_device_set_preview_window是set_preview_window的具体实现
SET_METHOD(set_callbacks), //展开后相当于set_callbacks : HAL_camera_device_set_callbacks
SET_METHOD(enable_msg_type), //同上
SET_METHOD(disable_msg_type),
SET_METHOD(msg_type_enabled),
SET_METHOD(start_preview),
SET_METHOD(stop_preview),
SET_METHOD(preview_enabled),
SET_METHOD(store_meta_data_in_buffers),
SET_METHOD(start_recording),
SET_METHOD(stop_recording),
SET_METHOD(recording_enabled),
SET_METHOD(release_recording_frame),
SET_METHOD(auto_focus),
SET_METHOD(cancel_auto_focus),
SET_METHOD(take_picture),
SET_METHOD(cancel_picture),
SET_METHOD(set_parameters),
SET_METHOD(get_parameters),
SET_METHOD(put_parameters),
SET_METHOD(send_command),
SET_METHOD(release),
SET_METHOD(dump),
};

先不说HAL中调用函数的具体实现,看看是service怎么调用的.
以start_preview为例.

camera.start_preview()    //应用程序
public native final void startPreview(); //此处调用JNI frameworks/base/core/java/android/hardware/Camera.java
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) //JNI frameworks/base/core/jni/android_hardware_Camera.cpp
sp<Camera> camera = get_native_camera(env, thiz, NULL); //获取cameraClient frameworks/base/core/jni/android_hardware_Camera.cpp
camera->startPreview(); //执行cameraClient的函数 frameworks/base/libs/camera/Camera.cpp.
status_t CameraService::Client::startPreview(); //service中函数的实现 frameworks/base/services/camera/libcameraservice/CameraService.cpp
status_t CameraService::Client::startCameraMode(camera_mode mode) //service中的调用 frameworks/base/services/camera/libcameraservice/CameraService.cpp
status_t CameraService::Client::startPreviewMode() //service最终调用 frameworks/base/services/camera/libcameraservice/CameraService.cpp
status_t startPreview() //调用到hardware的接口 frameworks/base/services/camera/libcameraservice/CameraHardwareInterface.h
mDevice->ops->start_preview(mDevice); //调用到HAL层的start_preview具体实现HAL_camera_device_start_preview. device/magiclab/common/libcamera/SecCameraHWInterface_zoom.cpp

OK,函数调用到这里也就完成了应用程序调用hardware内具体设备函数的流程.HAL的实现其实也就是实现上面每个函数.使它们协同合作而已.

-------------------

android从应用到驱动之—camera(2)---cameraHAL的实现的更多相关文章

  1. android从应用到驱动之—camera(2)---cameraHAL的实现

    本文是camera系列博客,上一篇是: android从应用到驱动之-camera(1)---程序调用流程 本来想用这一篇博客把cameraHAL的实现和流程都给写完的.搞了半天,东西实在是太多了.这 ...

  2. android从应用到驱动之—camera(1)---程序调用流程

    一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...

  3. android从应用到驱动之—camera(1)---程序调用流程[转]

    一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...

  4. (转)android从应用到驱动之—camera(1)---程序调用流程

    一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...

  5. Android 开发之 ---- 底层驱动开发(一) 【转】

    转自:http://blog.csdn.net/jmq_0000/article/details/7372783 版权声明:本文为博主原创文章,未经博主允许不得转载. 驱动概述 说到 Android ...

  6. 第一章 Android系统移植与驱动开发概述

    本书第一章首先简单概要地介绍了关于Android系统移植和驱动开发的相关内容. 所谓“移植”是指为特定的自己的设备,如手机定制Android的过程.自己开发一些程序(移植)装载在设备上,使得Andro ...

  7. Android 开发之 ---- 底层驱动开发(一)

    驱动概述 说到 android 驱动是离不开 Linux 驱动的.Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码).但 Andro ...

  8. Android 举例说明自己的定义Camera图片和预览,以及前后摄像头切换

    如何调用本地图片,并调用系统拍摄的图像上一博文解释(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自己定 ...

  9. Android系统移植与驱动开发----第一章

    第一章 Android系统移植与驱动开发 Android源代码定制完全属于自己的嵌入式系统,但是支持的设备不多,所以要移植,而在移植的过程中使用的不得不提的是驱动开发. Android系统构架主要包括 ...

随机推荐

  1. Android存储机制之Preference

    Preference提供了一种轻量级的数据存取方法,主要是数据比较少的配置信息.它以键值对的方式将数据保存在一个XML配置文件中. 使用Preference方式来存取数据,用到了SharedPrefe ...

  2. c#之反射总结

     1.了解什么事程序集 2.加载程序集 首先要加载需要加载的程序集,然后找到指定的类型,进而往下进行动态加载. 要加载的程序集中的内容: public class Class1:Person { pr ...

  3. Careercup - Google面试题 - 4557716425015296

    2014-05-03 21:57 题目链接 原题: Many sticks with length, every time combine two, the cost is the sum of tw ...

  4. 被git extensions给坑了,Not owner 解决办法

    我只遇到这一种情况,不能访问git文件主库, 清空以前的历史文件,包括默认配置文件,重新安装一遍git extension,然后设置账号和密码, 在打开bash设置私钥和公钥 把公钥添加到你的git的 ...

  5. ubuntu 12.04 搭建nginx + php + mysql +phpmyadmin

    1. 使用官方PPA安装 Nginx 最新版本,使用以下命令:sudo add-apt-repository ppa:nginx/stablesudo apt-get updatesudo apt-g ...

  6. UVA 10954 Add All 哈夫曼编码

    题目链接: 题目 Add All Time Limit:3000MS Memory Limit:0KB 问题描述 Yup!! The problem name reflects your task; ...

  7. CSS滤镜详解

    语法:STYLE="filter:filtername(fparameter1, fparameter2...)" (Filtername为滤镜的名称,fparameter1.fp ...

  8. C# mongodb [上]

    概述 MongoDB是一个高性能,开源,无模式的文档型数据库,使用C++开发.是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的.他支持的数据结构非常松散,是 ...

  9. 一些css效果积累

    悬浮效果: ul li a{text-decoration: none;color: black}  ul li a:hover{color: blue}   鼠标变小手 span:hover{cur ...

  10. tomcat 运行异常Cannot create PoolableConnectionFactory (到主机 的 TCP/IP 联接失败)(用户sa登录失败)

    这是在java web中启动tomcat遇到的问题,因为这个问题,整整折腾了两天的时间,找了很都解决方案,但终究还是不能正常.现在整理下这个问题的解决方案: 首先,出这个问题之前,请检查一下的问题,这 ...