接下來再來看JNI的對應函數。第一步,調用Camera::connect(cameraId)函數生成一個native的Camera對象。在這個函數內會通過binder向CameraService請求服務,如下:
sp Camera::connect(int cameraId)
{
LOGV("connect");
sp c = new Camera();
const sp& cs = getCameraService();
if (cs != 0) {
c->mCamera = cs->connect(c, cameraId);
}
if (c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
c.clear();
}
return c;
}
可以看到先是new了一個native Camera對象,然後把調用CameraService connect函數,傳入剛new出來的Camera對象並把返回值保存在mCamera變量中,此變量爲ICamera類型,看代碼就知道ICamera這個接口類提供了很多操作Camera的接口,以後拍照、preview等操作就要靠它來完成啦。
那CameraService的connect函數都做了些什麼呢?代碼如下:
sp CameraService::connect(
const sp& cameraClient, int cameraId) {
int callingPid = getCallingPid();
LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
sp client;
Mutex::Autolock lock(mServiceLock);
if (mClient[cameraId] != 0) {
client = mClient[cameraId].promote();
if (client != 0) {
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();
}
sp hardware = HAL_openCameraHardware(cameraId);
if (hardware == NULL) {
LOGE("Fail to open camera hardware (id=%d)", cameraId);
return NULL;
}
CameraInfo info;
HAL_getCameraInfo(cameraId, &info);
client = new Client(this, cameraClient, hardware, cameraId, info.facing,
callingPid);
mClient[cameraId] = client;
LOG1("CameraService::connect X");
return client;
}
刪去了一些無關緊要的代碼。可以看到CameraService里居然還有一個Client!首先試着從mClient裏取對應於camera id的client對象,如果找到並且請求的來源相同,就直接返回這個對象,但如果client對象存在但來自另一個不同的請求進程,那CameraService就會拒絕,因爲一個Camera只能被一個native Camera對象所擁有,可見用完Camera一定要及時釋放。如果mClient中找不到,那就先通過HAL_openCameraHardware函數拿到一個CameraHardwareInterface對象,通過它就獲得了與廠商自行實現的Camera HAL交流的渠道。接着new一個Client對象,傳入請求者對象、hardware HAL對象、camera id等,然後把這個對象返回,以後的具體操作就靠它啦。
一開始,我還對爲什麼CameraService裏還有Client感到疑惑,後來想明白是因爲系統可能不只有一個Camera,而CameraService只有一份,因此需要多個對象來對應多個Camera。至此,我們把請求進程與CameraService、Camera HAL連接了起來。總結下來,就是請求進程中得到了遠端CameraService中的Client對象,CameraService得到了請求進程的native Camera對象,並把它與Client聯繫起來,Client又跟Camera HAL聯繫起來,通過它獲得操作具體Camera的能力,當得到數據時可以通過保存的請求進程的native Camera對象進行回調。
JNI中第一步connect說完了,接下來的主要代碼如下:
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
sp context = new JNICameraContext(env, weak_this, clazz, camera);
context->incStrong(thiz);
camera->setListener(context);
// save context in opaque field
env->SetIntField(thiz, fields.context, (int)context.get());
new了一個JNICameraContext對象,把它設爲native Camera的listener,並把這個對象保存在java對象裏。JNICameraContext的作用主要是回調java層的函數,把圖像數據傳過去。