瞭解的不夠深入,應用功能實現後,再回頭細看Camera框架時,還是有些地方沒能連通,在網上也找了一些文章結合代碼來分析,不過能力有限,甚是痛苦。而且由於平臺不同,代碼的具體流程還是有區別。
下面所解內容的是基於高通8916平臺,也不知道能不能描述清楚,我盡力吧!
(參考的博文,樓主講的很好,只是平臺不同,有些地方的調用位置不同。http://blog.chinaunix.net/uid-2630593-id-3307176.html)
Camera C/S 的init過程
我們在上層應用,需要用到Camera時,打開Camera時調用的是Camera.open(i)函數,這個函數是由Camera.java給我們提供的接口。
下面要介紹的,是Camera的服務是如何註冊,和Camera客戶端是如何獲得系統提供的服務,實現打開Camera的過程。
先貼出Client端調用的大致流程圖,圖片有點模糊。
調用的相關文件有 CameraActivity.java(上層應用) ---> Camera.java ---> android_android_Camera.java (JNI) ---> Camera.java ---> CameraBase.cpp ---> ServiceManaager.java ---> CameraService.cpp ---> CameraClient.cpp ---> CameraHardwareInterface.cpp(HWI調用接口)
1、Camera 服務端的創建和註冊
和Camera服務的註冊相關的文件是Main_MediaServer.cpp,我們看到在該文件的main函數中 有個 CameraService::instantiate(); 再看instantiate()函數的真正實現是在BinderService.h 文件中,而真正相關的函數是BinService.h 中的publish()函數,在public()函數中,通過 addService( .....)方法添加相應的服務,而添加的該服務是由CameraService.h 的getServiceName(...)返回。
這樣,Camera服務就完成了在ServiceManager中的註冊,提供給Client隨時調用。
Main_MediaServer.cpp
int main(int argc, char** argv)
{
signal(SIGPIPE, SIG_IGN);
char value[PROPERTY_VALUE_MAX];
bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
pid_t childPid;
// FIXME The advantage of making the process containing media.log service the parent process of
// the process that contains all the other real services, is that it allows us to collect more
// detailed information such as signal numbers, stop and continue, resource usage, etc.
// But it is also more complex. Consider replacing this by independent processes, and using
// binder on death notification instead.
if (doLog && (childPid = fork()) != 0) {
// media.log service
//prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
// unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
strcpy(argv[0], "media.log");
sp<ProcessState> proc(ProcessState::self());
MediaLogService::instantiate();
ProcessState::self()->startThreadPool();
for (;;) {
siginfo_t info;
int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
if (ret == EINTR) {
continue;
}
if (ret < 0) {
break;
}
char buffer[32];
const char *code;
switch (info.si_code) {
case CLD_EXITED:
code = "CLD_EXITED";
break;
case CLD_KILLED:
code = "CLD_KILLED";
break;
case CLD_DUMPED:
code = "CLD_DUMPED";
break;
case CLD_STOPPED:
code = "CLD_STOPPED";
break;
case CLD_TRAPPED:
code = "CLD_TRAPPED";
break;
case CLD_CONTINUED:
code = "CLD_CONTINUED";
break;
default:
snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
code = buffer;
break;
}
struct rusage usage;
getrusage(RUSAGE_CHILDREN, &usage);
ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
info.si_pid, info.si_status, code,
usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.log"));
if (binder != 0) {
Vector<String16> args;
binder->dump(-1, args);
}
switch (info.si_code) {
case CLD_EXITED:
case CLD_KILLED:
case CLD_DUMPED: {
ALOG(LOG_INFO, "media.log", "exiting");
_exit(0);
// not reached
}
default:
break;
}
}
} else {
// all other services
if (doLog) {
prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
setpgid(0, 0); // but if I die first, don't kill my parent
}
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
#ifdef AUDIO_LISTEN_ENABLED
ALOGI("ListenService instantiated");
ListenService::instantiate();
#endif
AudioPolicyService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
}
BinderService.h
static voidinstantiate() {
publish(); }
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
CameraService.h
// Implementation of BinderService<T>
static char const* getServiceName() { return "media.camera"; }
2、Camera 客戶端獲取服務
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
我們在上層應用打開Camera時,是直接調用 Camera.java 函數給我們提供的open(id)函數,在Camera.java的open(...)函數中會new 一個Camera對象,在Camera(...)中 調用了native_setup(...)函數,我們看下native_setup(...)的聲明,就知道是個本地的native方法,所以該函數真正的實現是在JNI層的android_hardware_Camera.cpp 文件中。
Camera.java
public static Camera
open(int cameraId) {
return new Camera(cameraId);
}
Camera(int cameraId) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
/* ### QC ADD-ONS: START */
mCameraDataCallback = null;
mCameraMetaDataCallback = null;
/* ### QC ADD-ONS: END */
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
String packageName = ActivityThread.currentPackageName();
native_setup(new WeakReference<Camera>(this), cameraId, packageName);
}
private native final void
native_setup(Object camera_this, int cameraId,
String packageName);
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Camera的JNI層文件,android_hardware_Camera.cpp 。我們看在這個文件中,native_setup 函數的映射,相對應的函數是android_hardware_Camera_native_setup(...);
在android_hardware_Camera_native_setup函數中是調用了Camera::connect(...)方法,這個直接調用的就是Camera.cpp 文件中的connect(...)方法。
android_hardware_camera.cpp
{ "native_setup",
"(Ljava/lang/Object;ILjava/lang/String;)V",
(void*)android_hardware_Camera_native_setup
},
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jstring clientPackageName)
{
// Convert jstring to String16
const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
jsize rawClientNameLen = env->GetStringLength(clientPackageName);
String16 clientName(rawClientName, rawClientNameLen);
env->ReleaseStringChars(clientPackageName, rawClientName);
sp<Camera> camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
......
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
//JNICameraContext這個類是一個監聽類,用於處理底層Camera回調函數傳來的數據和消息
sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
context->incStrong((void*)android_hardware_Camera_native_setup);
camera->setListener(context);
// save context in opaque field
env->SetIntField(thiz, fields.context, (int)context.get());
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
我們看到在Camera.cpp文件的connect方法,真正調用的是CameraBase.cpp中的connect方法。
Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在CameraBase.cpp 的connect方法中,通過getCameraService()函數去獲取服務,因爲Camera Client和Service是通過binder機制來進行通信,所以在該connect方法中的(cs.get()->*fnConnectService)其實是直接執行CameraService中的connect方法。
CameraBase.cpp
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
status_t status = NO_ERROR;
const sp<ICameraService>& cs = getCameraService();
if (cs != 0) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera);
}
if (status == OK && c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
c.clear();
}
return c;
}
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if (gCameraService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
// const char* kCameraServiceName = "media.camera";
binder = sm->getService(String16(kCameraServiceName));
if (binder != 0) {
break;
}
ALOGW("CameraService not published, waiting...");
usleep(kCameraServicePollDelay);
} while(true);
if (gDeathNotifier == NULL) {
gDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(gDeathNotifier);
gCameraService = interface_cast<ICameraService>(binder);
}
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
}
ServiceManmager.java
public static IBinder
getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (直接粘貼下參考博文的描述,我的能力有限,樓主描述的很好了)
可以看出,該CameraService實例是通過binder獲取的,由binder機制可以知道,該服務就是CameraService一個實例。
然後執行服務端的connect()函數,並返回一個ICamera對象賦值給Camera 的mCamera, 服務端connect()返回的其實是它內部類client的一個實例。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
由上面的描述,我們知道Client通過binder獲得了一個CameraService的實例,而又由於binder機制,Clinet端通過(cs.get()->*fnConnectService)是直接調用到了CameraService.cpp 文件中的connect方法。我們分析 CameraService.cpp 的connect方法,會知道它會有自己內部的client,並最終會將其內部的client對象返回。
在該CammeraService.cpp 的connect方法中會調用 到connectFinishUnsafe(),去實現調用hal層接口,初始化一些參數。
CameraService.cpp
status_t CameraService::connect(const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<ICamera>& device) {
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
clientName8.string(), cameraId);
status_t status = validateConnect(cameraId, /*inout*/clientUid);
if (status != OK) {
return status;
}
sp<Client> client;
{
sp<BasicClient> clientTmp;
Mutex::Autolock lock(mServiceLock);
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
/*out*/clientTmp)) {
return -EBUSY;
} else if (client.get() != NULL) {
device = static_cast<Client*>(clientTmp.get());
return OK;
}
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
// If there are other non-exclusive users of the camera,
// this will tear them down before we can reuse the camera
if (isValidCameraId(cameraId)) {
// transition from PRESENT -> NOT_AVAILABLE
updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
cameraId);
}
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid());
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
client = new Camera2Client(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(),
deviceVersion);
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
return BAD_VALUE;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return INVALID_OPERATION;
}
status_t status = connectFinishUnsafe(client, client->getRemote());
if (status != OK) {
// this is probably not recoverable.. maybe the client can try again
// OK: we can only get here if we were originally in PRESENT state
updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
return status;
}
mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
getpid());
}
// important: release the mutex here so the client can call back
// into the service from its destructor (can be at the end of the call)
device = client;
return OK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在connectFinishUnsafe函數中,會去init 一個module,會直接調用到CameraClient.cpp 文件中的initialize函數。
status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
const sp<IBinder>& remoteCallback) {
status_t status = client->initialize(mModule);
if (status != OK) {
return status;
}
remoteCallback->linkToDeath(this);
return OK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在CameraClient.cpp 中是 new了一個CameraHardwareInterface對象,並調用該對象的initialize方法。以及callback的設置。
CameraClient.cpp
status_t CameraClient::initialize(camera_module_t *module) {
int callingPid = getCallingPid();
status_t res;
LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
// Verify ops permissions
res = startCameraOps();
if (res != OK) {
return res;
}
char camera_device_name[10];
snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(&module->common);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return NO_INIT;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)mCameraId);
// Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
return OK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
爲了屏蔽各硬件的差異,系統爲我們封裝了調用底層Camera接口的函數,就是 CameraHardwareInterface.h
在該文件的initialize方法中,我們看到 會通過 module->methods->open(),去實現Camera驅動設備節點的打開。
CameraHardwareInterface.h
status_t initialize(hw_module_t *module)
{
ALOGD("Opening camera %s", mName.string());
int rc = module->methods->open(module, mName.string(),
(hw_device_t **)&mDevice);
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
}
initHalPreviewWindow();
return rc;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (下面這段是參考博文的原文,粘貼下,其實我還不是很理解,有時間再看下)
void CameraService::onFirstRef()
{
LOG1("CameraService::onFirstRef");
BnCameraService::onFirstRef();
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule) < 0) {
ALOGE("Could not load camera HAL module");
mNumberOfCameras = 0;
}
else {
ALOGI("Loaded \"%s\" camera module", mModule->common.name);
mNumberOfCameras = mModule->get_number_of_cameras();
if (mNumberOfCameras > MAX_CAMERAS) {
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
}
if (mModule->common.module_api_version >=
CAMERA_MODULE_API_VERSION_2_1) {
mModule->set_callbacks(this);
}
CameraDeviceFactory::registerService(this);
}
}
瞭解HAL層的都知道hw_get_module函數就是用來獲取模塊的Hal stub,這裏是通過CAMERA_HARDWARE_MODULE_ID 獲取Camera Hal層的代理stub,並賦值給mModule,後面就可通過操作mModule完成對Camera模塊的控制。那麼onFirstRef()函數又是何時調用的?
onFirstRef()屬於其父類RefBase,該函數在強引用sp新增引用計數時調用,什麼意思?就是當 有sp包裝的類初始化的時候調用,那麼camera是何時調用的呢?可以發現在
sp Camera::connect(int cameraId)
{
LOGV("connect");
sp c = new Camera();
const sp& cs = getCameraService();
}
這個時候初始化了一個CameraService實例,且用Sp包裝,這個時候sp將新增計數,相應的CameraService實例裏面onFirstRef()函數完成調用。
CameraService::connect()返回client的時候,就表明客戶端和服務端連接建立。Camera完成初始化,可以進行拍照和preview等動作。
寫在後面
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
噠噠噠,不知不覺,好像整個過程也梳理了一遍,還是蠻有收穫的。
結合源碼和參考博文來看,真的對自己的幫助很大。
最開始,我也不相信自己會寫完,不過最後好像還好。能力有限,有些地方可能表達有誤,另外,再次說明,平臺不同,相應的代碼的調用位置也可能不同,不過大體的流程是一樣的。
最後最後的總結
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
剛開始接觸一個新的知識時,總會去查找一些資料,然後又很希望很希望能找到那種通過很俗、很易懂的表達方式,又或者說很口語話的方法,來將一些東西將儘可能講明白的文章。後來又發現,其實別人講的再通俗易懂,如果自己沒有去跟讀代碼,沒有去用自己的思路、自己的語言去總結,恐怕效果也會不好。
總的來說,整篇文章的思路就是,在系統啓動的時候,會去註冊和啓動 Camera服務,Camera服務註冊完成後,我們就可以隨時去調用這個服務,讓這個服務幫助我們去實現我們想要的功能(比如打開camera、預覽......)