Android Camera 流程學習記錄(二)—— Camera Open 呼叫流程
阿新 • • 發佈:2019-02-02
簡介
- 這一章裡,我們將
Camera.java
中的open()
方法作為切入點。作為開啟攝像頭的方法,無論哪種 Camera 應用都需要呼叫到它。 - 從
Camera.open()
被呼叫開始,這一指令是如何通過 Framework 層走到 C/C++ 層,又是如何進入 HAL 層從而使得指令能夠到達裝置端。 - 通過追蹤原始碼,我們可以比較清晰地瞭解整個過程。
- 接下來按照
Framework -> Android Runtime -> C/C++ Libraries -> HAL
的順序去分析整個呼叫流程。
Open flow
1. Framework
1.1 Camera.java
- 路徑:
frameworks/base/core/java/android/hardware/Camera.java
- 首先從
Open()
方法開始:
- 獲取
Camera
裝置的個數。 - 依次獲取裝置資訊,如果是獲取到後置攝像頭(預設),則呼叫
new Camera(int)
構造對應的攝像頭例項。
- 獲取
- 註釋翻譯:
- 構造一個新的攝像頭物件,以獲取第一個後置攝像頭。
- 若裝置中沒有後置攝像頭,則返回
null
。
- NOTE:還有一個方法
open(int)
,它可以直接指定開啟的攝像頭。
/***
* Creates a new Camera object to access
* the first back-facing camera on the
* device. If the device does not have a back-facing camera,
* this returns null.
* @see #open(int)
*/
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;
}
Camera(int cameraId)
:
- 通過呼叫
cameraInitNormal(Id)
方法對指定攝像頭進行初始化。
- 通過呼叫
/** used by Camera#open, Camera#open(int) */
Camera(int cameraId) {
int err = cameraInitNormal(cameraId);
if (checkInitErrors(err)) {
if (err == -EACCES) {
throw new RuntimeException("Fail to connect to camera service");
} else if (err == -ENODEV) {
throw new RuntimeException("Camera initialization failed");
}
// Should never hit this.
throw new RuntimeException("Unknown camera error");
}
}
cameraInitNormal(int cameraId)
:
- 指定
halVersion
引數。 - 呼叫
cameraInitVersion(int cameraId, int halVersion)
。
- 指定
private int cameraInitNormal(int cameraId) {
return cameraInitVersion(cameraId,
CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
}
cameraInitVersion(int cameraId, int halVersion)
:
- 將各個回撥函式置空。
Looper
的作用沒有仔細研究,從程式碼邏輯上看,可能與事件的監聽(需要迴圈操作)有關。- 通過
Looper
對事件處理物件進行例項化後,就呼叫native_setup
方法進入JNI(Java Native Interface)
庫中呼叫對應的函式。 - 至此,
open()
方法開始進入Android Runtime
層。
private int cameraInitVersion(int cameraId,
int halVersion) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
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;
}
return native_setup(new WeakReference<Camera>(this),
cameraId, halVersion,
ActivityThread.currentOpPackageName());
}
1.2 Framework 中流程簡圖
2. Android Runtime
2.1 android_hardware_Camera.cpp
- 路徑:
frameworks/base/core/jni/android_hardware_Camera.cpp
native_setup()
:
- 剛開始要先把
clientPackageName
做一個型別轉換,變成clientName
。 - 建立一個
Camera
型別的StrongPointer(sp)
。 - 通過函式
Camera::connect()
或Camera::connectLegacy()
,讓客戶端與服務端進行連線,並返回相應的Camera
例項。 - 最後對返回的例項進行一些基本的檢查,並儲存上下文。
- 在
connect()
的時候,就進入了C/C++ Libraries
的 C/S 結構中,而Camera
則屬於Client
。
- 剛開始要先把
// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env,
jobject thiz, jobject weak_this,
jint cameraId, jint halVersion,
jstring clientPackageName)
{
// convert jstring to String16(clientPackageName -> clientName)
......
......
sp<Camera> camera;
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
/***** NOTE THIS *****/
// Default path: hal version is don't care, do normal camera connect.
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID,
Camera::USE_CALLING_PID);
} else {
jint status = Camera::connectLegacy(cameraId,
halVersion, clientName,
Camera::USE_CALLING_UID, camera);
if (status != NO_ERROR) {
return status;
}
}
if (camera == NULL) {
return -EACCES;
}
// make sure camera hardware is alive
if (camera->getStatus() != NO_ERROR) {
return NO_INIT;
}
// save context in opaque field
......
......
}
2.2 Runtime 中流程簡圖
3. C/C++ Libraries
3.1 Camera
3.1.1 Camera.h
- 位置:
frameworks/av/include/camera/Camera.h
- 注意
CameraTraits<Camera>
的結構體:
template <>
struct CameraTraits<Camera>
{
typedef CameraListener TCamListener;
typedef ::android::hardware::ICamera TCamUser;
typedef ::android::hardware::ICameraClient TCamCallbacks;
typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
(const sp<::android::hardware::ICameraClient>&,
int, const String16&, int, int,
/*out*/
sp<::android::hardware::ICamera>*);
static TCamConnectService fnConnectService;
};
3.1.2 Camera.cpp
- 位置:
framework/av/camera/Camera.cpp
- 注意
fnConnectService
是對應到ICameraService::connect
函式的。
CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
&::android::hardware::ICameraService::connect;
Camera::connect
:
- 這裡直接呼叫了
CameraBaseT::connect()
這是定義在CameraBase.cpp
中的函式。
- 這裡直接呼叫了
sp<Camera> Camera::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid)
{
return CameraBaseT::connect(cameraId,
clientPackageName, clientUid, clientPid);
}
3.2 CameraBase
3.2.1 CameraBase.h
- 位置:
frameworks/av/include/camera/CameraBase.h
- 注意模板資訊:
TCam
對應Camera
。TCamTraits
對應CameraTraits<Camera>
。
template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
- 注意類成員變數宣告部分:
- 即可知道
CameraBaseT
對應CameraBase<Camera>
。
- 即可知道
sp<TCamUser> mCamera;
status_t mStatus;
sp<TCamListener> mListener;
const int mCameraId;
/***** NOTE THIS *****/
typedef CameraBase<TCam> CameraBaseT;
3.2.2 CameraBase.cpp
- 位置:
framework/av/camera/CameraBase.cpp
connect()
:
- 例項化一個
Camera
- 通過
Camera
獲取ICameraClient
指標。 - 通過
getCameraService()
函式獲取ICameraService
。 - 通過
ICameraService::connect()
函式獲得一個mCamera
, 即ICamera
例項。 - 將
ICamera
例項與Binder
建立聯絡。
- 例項化一個
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid)
{
ALOGV("%s: connect", __FUNCTION__);
/***** NOTE THIS *****/
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
const sp<::android::hardware::ICameraService> cs = getCameraService();
binder::Status ret;
if (cs != nullptr) {
/***** NOTE THIS *****/
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
ret = (cs.get()->*fnConnectService)(cl, cameraId,
clientPackageName, clientUid,
clientPid, /*out*/ &c->mCamera);
}
if (ret.isOk() && c->mCamera != nullptr) {
/***** NOTE THIS *****/
IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
(cs != nullptr) ? "Service not available" : ret.toString8().string());
c.clear();
}
return c;
}
getCameraService()
:
- 注意,
gCameraService
是一個ICameraService
。 - 首先呼叫
ICameraService
的get
函式,如果能獲取到ICameraService
則返回。 - 若沒有返回,則通過
IServiceManager
來獲取一個ICameraService
,這個過程中主要是通過IBinder
來進行資料的獲取的,其中機制暫時忽略,只要知道通過Binder
我們獲取了一個ICameraService
就好。
- 注意,
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
/***** NOTE THIS *****/
if (gCameraService.get() == 0) {
char value[PROPERTY_VALUE_MAX];
property_get("config.disable_cameraservice", value, "0");
if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) {
return gCameraService;
}
/***** NOTE THIS *****/
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
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);
/***** NOTE THIS *****/
gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
}
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
}
3.3 ICameraService
- NOTE:
- 這一節主要是瞭解一下關於 Binder 通訊中的一些內部邏輯。
- 實際上在
CameraBase
中,所呼叫的connect
對應的是CameraService::connect()
,在下一節中再進行分析。
3.3.1 ICameraService.aidl
- 位置:
frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
aidl
是一種內部程序通訊的描述語言,通過它我們可以定義通訊的介面。- 註釋:
- 這裡定義了執行在媒體服務端的,本地攝像頭服務的 Binder 介面
/**
* Binder interface for the native camera service running in mediaserver.
*
* @hide
*/
connect
介面:
- 這裡的註釋說明了,這個方法呼叫的是舊的
Camera API
,即API 1
。
- 這裡的註釋說明了,這個方法呼叫的是舊的
/**
* Open a camera device through the old camera API
*/
ICamera connect(ICameraClient client,
int cameraId,
String opPackageName,
int clientUid, int clientPid);
3.3.2 ICameraService.cpp
- 位置:
out/target/product/generic/obj/SHARED_LIBRARIES/libcamera_client_intermediates/aidl-generated/src/aidl/android/hardware/ICameraService.cpp
out
資料夾是原始碼編譯後才生成的.- 這個
ICameraService.cpp
以及其標頭檔案ICameraService.h
都是根據其對應的aidl
檔案自動生成的。 BpCameraService::connect()
:
- 注意,這裡是
BpCameraservice
,它繼承了ICameraService
,同時也繼承了BpInterface
。 Parcel
可以看成是Binder
通訊中的資訊傳遞中介。- 首先把相應的資料寫入
Parcel
。 - 然後呼叫遠端介面
remote()
中的處理函式transact()
。 - 最後通過返回的
reply
資料判斷是否有error
。
- 注意,這裡是
::android::binder::Status BpCameraService::connect(const ::android::sp<::android::hardware::ICameraClient>& client,
int32_t cameraId, const ::android::String16& opPackageName,
int32_t clientUid, int32_t clientPid,
::android::sp<::android::hardware::ICamera>* _aidl_return)
{
::android::Parcel _aidl_data;
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
/***** NOTE THIS *****/
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeStrongBinder(::android::hardware::ICameraClient::asBinder(client));
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeInt32(cameraId);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeString16(opPackageName);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeInt32(clientUid);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeInt32(clientPid);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
/***** NOTE THIS *****/
_aidl_ret_status = remote()->transact(ICameraService::CONNECT, _aidl_data, &_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
if (!_aidl_status.isOk()) {
return _aidl_status;
}
_aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}
BnCameraService::onTransact()
:
- 訊息處理函式。
- 這個函式太長,只擷取
CONNECT
相關的一段。 BpCameraService
通過Binder
封裝了介面,而BnCameraService
則具體實現介面。- 注意到這裡一一接收了
Bp
傳來的資料,然後呼叫了具體的connect
函式獲取ICamera
並且返回。
case Call::CONNECT:
{
::android::sp<::android::hardware::ICameraClient> in_client;
int32_t in_cameraId;
::android::String16 in_opPackageName;
int32_t in_clientUid;
int32_t in_clientPid;
/***** NOTE THIS *****/
::android::sp<::android::hardware::ICamera> _aidl_return;
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
_aidl_ret_status = _aidl_data.readStrongBinder(&in_client);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_data.readInt32(&in_cameraId);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_data.readString16(&in_opPackageName);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_data.readInt32(&in_clientUid);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_data.readInt32(&in_clientPid);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
/***** NOTE THIS *****/
::android::binder::Status _aidl_status(connect(in_client, in_cameraId, in_opPackageName, in_clientUid, in_clientPid, &_aidl_return));
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
/***** NOTE THIS *****/
_aidl_ret_status = _aidl_reply->writeStrongBinder(::android::hardware::ICamera::asBinder(_aidl_return));
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
}
break;
3.4 ICamera
- 這一節我們回到
CameraBase
關於connect()
函式的呼叫中。
3.4.1 ICamera.cpp
- 位置:
frameworks/av/camera/ICamera.cpp
BpCamera
類只提供給Client
呼叫的介面。- 在
BpCamera
類中,有connect()
函式:
virtual status_t connect(const sp<ICameraClient>& cameraClient)
{
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(cameraClient));
remote()->transact(CONNECT, data, &reply);
return reply.readInt32();
}
- 而
BnCamera
類應負責實現介面,但這裡有一點特殊,它是通過CameraService::Client
來實現具體介面的。 - 在
BnCamera
類中,onTransact
函式則有相應的處理:
case CONNECT: {
CHECK_INTERFACE(ICamera, data, reply);
sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
reply->writeInt32(connect(cameraClient));
return NO_ERROR;
} break;
3.4.2 CameraService.cpp
- 位置:
frameworks/av/services/camera/libcameraservice/CameraService.cpp
connect()
:
- 注意這裡真正實現邏輯是在
connectHelper()
函式中。 - 獲得一個客戶端例項並且通過
*device
返回。
- 注意這裡真正實現邏輯是在
Status CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
int clientPid,
/*out*/
sp<ICamera>* device) {
ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8::format("%d", cameraId);
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
/*legacyMode*/ false, /*shimUpdateOnly*/ false,
/*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
*device = client;
return ret;
}
3.4.3 CameraService.h
- 位置:
frameworks/av/services/camera/libcameraservice/CameraService.h
- 注意這個檔案中定義了 CameraService::Client 類,這個類通過它的子類 CameraClient 真正實現了 ICamera 的介面。
connectHelper()
:
- 這個函式實現比較長,擷取其中的一段。
- 首先,如果客戶端例項已經存在於
MediaRecorder
,則直接將其取出返回。 - 若不存在,則先獲取
deviceVersion
,然後再呼叫makeClient()
函式建立一個客戶端。 - 建立客戶端後,需要呼叫其
initialize()
函式進行初始化,注意其傳入的引數是mModule
,這個引數是連線Libraries
與HAL
的關鍵引數。
sp<BasicClient> clientTmp = nullptr;
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
if ((err = handleEvictionsLocked(cameraId,
originalClientPid, effectiveApiLevel,
IInterface::asBinder(cameraCb), clientName8,
/*out*/&clientTmp,
/*out*/&partial)) != NO_ERROR) {
/***** do something *****/
}
/***** NOTE THIS *****/
if (clientTmp.get() != nullptr) {
// Handle special case for API1 MediaRecorder where the existing client is returned
device = static_cast<CLIENT*>(clientTmp.get());
return ret;
}
// give flashlight a chance to close devices if necessary.
mFlashlight->prepareDeviceOpen(cameraId);
// TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs
int id = cameraIdToInt(cameraId);
if (id == -1) {
ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,
cameraId.string());
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
"Bad camera ID \"%s\" passed to camera open", cameraId.string());
}
int facing = -1;
/***** NOTE THIS *****/
int deviceVersion = getDeviceVersion(id, /*out*/&facing);
sp<BasicClient> tmp = nullptr;
if(!(ret = makeClient(this, cameraCb,
clientPackageName, id, facing, clientPid,
clientUid, getpid(), legacyMode, halVersion,
deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());
LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
__FUNCTION__);
/***** NOTE THIS *****/
if ((err = client->initialize(mModule)) != OK) {
/***** do somthing *****/
}
// Update shim paremeters for legacy clients
if (effectiveApiLevel == API_1) {
// Assume we have always received a Client subclass for API1
sp<Client> shimClient = reinterpret_cast<Client*>(client.get());
String8 rawParams = shimClient->getParameters();
CameraParameters params(rawParams);
auto cameraState = getCameraState(cameraId);
if (cameraState != nullptr) {
cameraState->setShimParams(params);
} else {
ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",
__FUNCTION__, cameraId.string());
}
}
if (shimUpdateOnly) {
// If only updating legacy shim parameters, immediately disconnect client
mServiceLock.unlock();
client->disconnect();
mServiceLock.lock();
} else {
// Otherwise, add client to active clients list
finishConnectLocked(client, partial);
}
} // lock is destroyed, allow further connect calls
// 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;
3.4.4 CameraClient.cpp
- 位置:
frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp
- 從檔案位置也可以看得出,我們現在走的都是
Camera API 1
的流程。 CameraClient
繼承了CameraService::Client
。CameraClient::initialize()
:
- 獲取
CameraHardwareInterface
例項。 - 對
mHardware
進行初始化。 - 設定三個回撥函式(這裡與資料流密切相關)
- 獲取
status_t CameraClient::initialize(CameraModule *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);
/***** NOTE THIS *****/
mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(module);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return res;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)(uintptr_t)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;
}
- 至此,整個
Libraries
層的open
流程就結束了,接下來進入到HAL
層。
3.5 Libraries 中流程簡圖
(NOTE:圖中 IcameraService
到 ICamera
的箭頭中標有 connect()
,表示的是 ICameraService
的例項呼叫其 connect()
函式後,output 為 ICamera
的例項。)
(2018.5.10:現在看看早先這幾篇 Camera 分析文章,感覺有許多流程沒有畫清楚。如果有時間的話,再把 Android 8.1 的 Camera open 流程分析分析吧,加上了 Trable 機制,還是值得再去探究的。)
4. HAL
4.1 CameraHardwareInterface.h
- 位置:
frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
initialize()
:
- 通過
module
,從HAL
層的庫中呼叫相關的函式獲取Camera
裝置資訊。 - 根據模組
API
的版本,判斷是用open
函式還是用openLegacy
。 - 呼叫
open
後,通過HAL
中的庫,我們的指令就能傳遞到Linux Kernel
,從而下達到具體的裝置上。(與具體的驅動相關,暫時不去分析) - 最後初始化預覽視窗。
- 通過
status_t initialize(CameraModule *module)
{
ALOGI("Opening camera %s", mName.string());
camera_info info;
status_t res = module->getCameraInfo(atoi(mName.string()), &info);
if (res != OK) {
return res;
}
int rc = OK;
if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
// Open higher version camera device as HAL1.0 device.
rc = module->openLegacy(mName.string(),
CAMERA_DEVICE_API_VERSION_1_0,
(hw_device_t **)&mDevice);
} else {
rc = module->open(mName.string(), (hw_device_t **)&mDevice);
}
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
}
initHalPreviewWindow();
return rc;
}
- 至此,我們所研究的
Camera Open
整個呼叫流程就已經比較清晰了。
小結
- 在這篇筆記中,我們主要是從
Camera.open()
方法被呼叫開始,對原始碼進行追溯,從而一層層地瞭解了它的一個呼叫的過程,與過程中比較重要的一些邏輯。 - 通過這一輪追溯,我們就可以對
Camera
架構有一個更深刻的認識,但是其中可能還有一些知識點沒有理清,不過我認為不會影響對於整個架構的瞭解。
- 我認為比較難去理解的就是
Libraries
中,關於客戶端與服務端互動的部分。這一部分我在閱讀原始碼的時候花了很多時間去理解,實際上目前為止,也只是有比較基礎的概念。對這部分,還有很多更深入的內容需要去探究,在系統原始碼分析1一書中,有關於Binder
的很詳細的解析,通過深入瞭解Binder
機制,我認為應該能更清楚C/S
相關的內容。
- 實際上,在與
HAL
層接觸的這一部分,mModule
這個變數非常關鍵,但是我認為它的相關內容單獨放在一篇筆記中分析,會比較清晰,所以下一篇筆記就先探究module
相關的內容。
- 《Android 系統原始碼情景分析》 ↩