CameraService啟動
CameraService是在MediaServer啟動過程中進行的
main_mediaserver.cpp (frameworks\av\media\mediaserver)
......
AudioFlinger::instantiate(); //audioflinger服務,音訊相關
MediaPlayerService::instantiate(); //mediaplayerservice,媒體播放相關
CameraService::instantiate();//CameraService
AudioPolicyService::instantiate(); //音訊相關
......複製程式碼
在 main函式中會執行到CameraService::instantiate(), CameraService 本身並沒有實現這個方法
CameraService.cpp (frameworks\av\services\camera\libcameraservice)
CameraService.h (frameworks\av\services\camera\libcameraservice)
BinderService.h (frameworks\native\include\binder)
class CameraService :
public BinderService<CameraService>,
public BnCameraService,
public IBinder::DeathRecipient,
public camera_module_callbacks_t
{
......
}複製程式碼
在其父類中尋找instantiate()函式,BinderService是一個模板類
template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false) { //BinderService::publish
sp<IServiceManager> sm(defaultServiceManager()); //拿到ServiceManager的Bp
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated); //這裡的SERVICE就是CameraService
}
.....
static void instantiate() { publish(); } //BinderService::instantiate
.....
};複製程式碼
這裡會new CameraService(),
CameraService::CameraService()
:mSoundRef(0), mModule(0)
{
ALOGI("CameraService started (pid=%d)", getpid());
gCameraService = this; //儲存一個本地指標
for (size_t i = 0; i < MAX_CAMERAS; ++i) {
mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
}
this->camera_device_status_change = android::camera_device_status_change;
}複製程式碼
到這裡,CameraService就啟動了。
Camera連線過程
Camera.java (frameworks\base\core\java\android\hardware)
Camera.cpp (frameworks\av\camera)
android_hardware_Camera.cpp (frameworks\base\core\jni)
從java->jni->CPP的典型過程
首先從Camera.java入手,這裡通過open()方法,建立Camera
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
public static Camera open() {
int numberOfCameras = getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
return new Camera(i);
}
}
return null;
}複製程式碼
兩個open()方法,預設開啟後置攝像頭,new Camera()物件,
Camera(int cameraId) {
int err = cameraInitNormal(cameraId);//做事的主要地方
if (checkInitErrors(err)) {
switch(err) { //通過返回的錯誤資訊,拋不同的異常資訊
case EACCESS:
throw new RuntimeException("Fail to connect to camera service");
case ENODEV:
throw new RuntimeException("Camera initialization failed");
default:
// Should never hit this.
throw new RuntimeException("Unknown camera error");
}
}
}複製程式碼
接下來看下程式碼,最後會落腳到哪一塊呢?
private int cameraInitNormal(int cameraId) {
//這裡的CAMERA_HAL_API_VERSION_NORMAL_CONNECT後面會提到用來區別不同的connect
return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
}
......
private int cameraInitVersion(int cameraId, int halVersion) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null; //初始化幾個callback和一些變數
Looper looper; //mEventHandler後面會講到是對底層上報內容的處理handler
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();
return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}複製程式碼
可以看到native_setup是一個native方法,具體實現在
android_hardware_Camera.cpp (frameworks\base\core\jni)
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
......
sp<Camera> camera;
//之前在建立Camera物件的時候設定的一個常量,此時走到connect方法
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
// Default path: hal version is don't care, do normal camera connect.
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
} else {
jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
Camera::USE_CALLING_UID, camera);
if (status != NO_ERROR) {
return status;
}
}
......
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
context->incStrong((void*)android_hardware_Camera_native_setup);
camera->setListener(context);//listener用於處理底層資料上報
// save context in opaque field
env->SetLongField(thiz, fields.context, (jlong)context.get());
return NO_ERROR;
}複製程式碼
從JNI往下就是CPP,繼續探尋Camera連線過程
Camera.cpp (frameworks\av\camera)
CameraBase.cpp (frameworks\av\camera)
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid)
{ //CameraBaseT為模板類
return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}複製程式碼
CameraBase中connect函式模板替換成
sp<Camera> CameraBase<Camera, CameraTraits<Camera>>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<Camera> c = new Camera(cameraId);
sp<ICameraClient> cl = c;
status_t status = NO_ERROR;
const sp<ICameraService>& cs = getCameraService();//獲取CameraService的Bp
if (cs != 0) {
//這裡TCamConncectService是一個函式指標,指向的是ICameraService中的connect方法
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera);
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;
}複製程式碼
這裡可能有點繞,稍微講解一下,模板上
template
template <typename TCam>
struct CameraTraits {
};
template <typename TCam, typename TCamTraits = CameraTraits<TCam> >複製程式碼
然後我們再到Camera.h中看
template <>
struct CameraTraits<Camera>
{
typedef CameraListener TCamListener;
typedef ICamera TCamUser;
typedef ICameraClient TCamCallbacks;
typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
int, const String16&, int,
/*out*/
sp<ICamera>&);
static TCamConnectService fnConnectService;
};複製程式碼
中間有些過程,應該好理解了,這裡繞了一下,最後落腳到ICameraService.cpp中的connect方法,這一部分涉及到Binder機制比較多,暫時先不講解具體內容,注意呼叫的地方即可。
ICameraService.cpp (frameworks\av\camera)
// connect to camera service (android.hardware.Camera)
virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
const String16 &clientPackageName, int clientUid,
/*out*/
sp<ICamera>& device)
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
data.writeStrongBinder(cameraClient->asBinder());
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
remote()->transact(BnCameraService::CONNECT, data, &reply);//通過binder遠端呼叫傳入的code為BnCameraservice::CONNECT
if (readExceptionCode(reply)) return -EPROTO;
status_t status = reply.readInt32();
if (reply.readInt32() != 0) {
device = interface_cast<ICamera>(reply.readStrongBinder());//轉換為BpCamera
}
return status;
}複製程式碼
接下來或執行到BnCameraService的onTransact()方法,主要就是switch_case,上面傳入的是CONNECT
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
......
case CONNECT: {
CHECK_INTERFACE(ICameraService, data, reply);
sp<ICameraClient> cameraClient =
interface_cast<ICameraClient>(data.readStrongBinder());
int32_t cameraId = data.readInt32();
const String16 clientName = data.readString16();
int32_t clientUid = data.readInt32();
sp<ICamera> camera;
status_t status = connect(cameraClient, cameraId,
clientName, clientUid, /*out*/camera);
//這裡BnCameraService並沒有實現connect函式,實際實現在CameraService中
reply->writeNoException();
reply->writeInt32(status);
if (camera != NULL) {
reply->writeInt32(1);
reply->writeStrongBinder(camera->asBinder());
} else {
reply->writeInt32(0);
}
return NO_ERROR;
} break;
......
}
}複製程式碼
我們來看一下CameraService中的connect方法到底做了哪些事情
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;
}
//Client類繼承BnCamera BasicClient
sp<Client> client;
{
Mutex::Autolock lock(mServiceLock);
sp<BasicClient> clientTmp;
//判斷當前裝置是否被佔有或者是重複請求
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
/*out*/clientTmp)) {
return -EBUSY;//從返回結果可以看出這個函式的用途
} else if (client.get() != NULL) {
device = static_cast<Client*>(clientTmp.get());
return OK;
}
//考慮當前沒有其他程式佔用攝像頭,走到下一步
status = connectHelperLocked(/*out*/client,
cameraClient,
cameraId,
clientPackageName,
clientUid,
callingPid);
if (status != OK) {
return status;
}
}
// 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作為傳出引數
device = client;
return OK;
}複製程式碼
繼續跟蹤到connectHelperLocked()函式中
status_t CameraService::connectHelperLocked(
/*out*/
sp<Client>& client,
/*in*/
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
int callingPid,
int halVersion,
bool legacyMode) {
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
if (halVersion < 0 || halVersion == deviceVersion) {
// Default path: HAL version is unspecified by caller, create CameraClient
// based on device version reported by the HAL.
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
//建立CameraClient物件
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(), legacyMode);
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
client = new Camera2Client(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(), legacyMode);
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
return BAD_VALUE;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return INVALID_OPERATION;
}
} else {
// A particular HAL version is requested by caller. Create CameraClient
// based on the requested HAL version.
if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
// Only support higher HAL version device opened as HAL1.0 device.
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(), legacyMode);
} else {
// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
" opened as HAL %x device", halVersion, deviceVersion,
CAMERA_DEVICE_API_VERSION_1_0);
return INVALID_OPERATION;
}
}
//主要是對CameraClient的初始化過程
status_t status = connectFinishUnsafe(client, client->getRemote());
if (status != OK) {
// this is probably not recoverable.. maybe the client can try again
return status;
}
//儲存CameraClient物件到本地陣列中,以備CameraService使用
mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
getpid());
return OK;
}複製程式碼
這裡的client建立成功後會賦值給device,而device就是之前連線過程中的傳入引數,到這裡Camera的連線過程就基本完成了。
本文主要順著程式碼理了一下過程,具體細節地方可能有所忽略。主要的流程圖如下,歡迎交流指正。
備註
本文中程式碼使用的是Android5.0原始程式碼,最新的Android N版本除了把CameraService單獨拎出來,其他的內容基本上大同小異。目前只關注API1,後續應該會補上API2的內容
版權宣告:本文為博主原創文章,未經博主允許不得轉載。
個人微信公眾號,歡迎大家掃碼關注,Android技術交流或者諮詢。