首先,Package层的Camera.java会调用Framework层的Camera.java的open函数,传入camera id。这个函数是个static函数,它只是new了一个Camera对象并返回。在Camera的构造函数中,最主要的就是调用JNI层的native_setup函数,传入两个参数:对象自身的weak引用,以及camera id。使用weak reference的目的是不影响Camera对象的垃圾回收,因为JNI层保存这个对象主要是用于回调。
接下来再来看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层的函数,把图像数据传过去。
阅读(8134) | 评论(0) | 转发(0) |