今年一進公司就開始搞相機開發,一直是在搞相機應用層,不過自己的學習心一直沒停,閑暇之餘就研究一下相機的framework、HAL層的東西,平時工作中碰到的和自己接觸到的,相機中最複雜的就是預覽了,有了一些體會也不想放下,是以決定寫一系列關于Android相機的部落格,把自己學習到的東西記錄下來。
說起Android相機的東西,從應用層的角度來看,基本就是四個重要的節點了:openCamera、createCaptureSession、preview、capture,最複雜的就是preview了,要了解preview,那麼就要求大家對Android的View顯示系統有一定的了解,才能更好的了解相機的預覽。相機的預覽其實就是使用預覽區的SurfaceView對應的surface建立一條預覽流,然後framework從預覽surface當中擷取到顯示buffer,這裡用于顯示的buffer會根據數量來擷取,華為手機的相機framework+HAL兩部分一般總共需要7個buffer,每個buffer都對應預覽區的一屏的大小,它就是HAL、算法各層填充完畢後,要交給SurfaceFlinger用于顯示的預覽區大小的所有像素點的byte數組,這7個buffer每次在CameraServer程序擷取一個,然後通過HIDL下發給CameraDaemon程序,交給算法、HAL層進行着色渲染,完成後再通過CameraServer程序交給SurfaceFlinger,最後顯示在螢幕上,這樣不斷的輪轉,我們就看到了預覽區會不斷的變動,這裡的buffer輪轉也就是相機最核心的部分了。我們後期的部落格具體在講關于buffer輪轉的知識。
這節我們先來說說從應用層調用openCamera之後的執行邏輯。openCamera的方法實作是在frameworks\base\core\java\android\hardware\camera2\CameraManager.java類中完成的,CameraManager和我們應用中經常使用的WindowManager、PackageManager一樣,都可以通過context上下文擷取到,它也是在frameworks\base\core\java\android\app\SystemServiceRegistry.java類中通過Context.CAMERA_SERVICE鍵值注冊的,源碼如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiQ3chVEa0V3bT9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwVPrRlTwMGVOJTSq1kZShVW1xmMjZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TM2QTNxUTN1EDOyEDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
我們拿到CameraManager類的對象之後,就可以調用它的openCamera方法來打開相機了,CameraManager類的openCamera方法的源碼如下:
@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {
openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
}
這個方法的實作很簡單,就是調用openCameraForUid來進一步處理,我們先來看看調用該方法需要傳遞的參數,第一個表示要打開的目标Camera的id,華為手機上該值一般有兩個:0和1,0表示後攝,當然也是主攝,1表示前攝,我們怎麼知道該值的取值呢?可以通過調用CameraManager類的getCameraIdList()方法來擷取,該方法會将目前已經注冊成功的camera硬體對應的id清單傳回給我們應用層,硬體注冊都是驅動層的東西了,那一步離我們現在的階段還很遠。我們再來看一下第二個參數CameraDevice.StateCallback ,它是定義在 frameworks\base\core\java\android\hardware\camera2\CameraDevice.java類中的一個内部類,StateCallback類的定義源碼如下:
public static abstract class StateCallback {
/**
* An error code that can be reported by {@link #onError}
* indicating that the camera device is in use already.
*
* <p>
* This error can be produced when opening the camera fails due to the camera
* being used by a higher-priority camera API client.
* </p>
*
* @see #onError
*/
public static final int ERROR_CAMERA_IN_USE = 1;
/**
* An error code that can be reported by {@link #onError}
* indicating that the camera device could not be opened
* because there are too many other open camera devices.
*
* <p>
* The system-wide limit for number of open cameras has been reached,
* and more camera devices cannot be opened until previous instances are
* closed.
* </p>
*
* <p>
* This error can be produced when opening the camera fails.
* </p>
*
* @see #onError
*/
public static final int ERROR_MAX_CAMERAS_IN_USE = 2;
/**
* An error code that can be reported by {@link #onError}
* indicating that the camera device could not be opened due to a device
* policy.
*
* @see android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName, boolean)
* @see #onError
*/
public static final int ERROR_CAMERA_DISABLED = 3;
/**
* An error code that can be reported by {@link #onError}
* indicating that the camera device has encountered a fatal error.
*
* <p>The camera device needs to be re-opened to be used again.</p>
*
* @see #onError
*/
public static final int ERROR_CAMERA_DEVICE = 4;
/**
* An error code that can be reported by {@link #onError}
* indicating that the camera service has encountered a fatal error.
*
* <p>The Android device may need to be shut down and restarted to restore
* camera function, or there may be a persistent hardware problem.</p>
*
* <p>An attempt at recovery <i>may</i> be possible by closing the
* CameraDevice and the CameraManager, and trying to acquire all resources
* again from scratch.</p>
*
* @see #onError
*/
public static final int ERROR_CAMERA_SERVICE = 5;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"ERROR_"}, value =
{ERROR_CAMERA_IN_USE,
ERROR_MAX_CAMERAS_IN_USE,
ERROR_CAMERA_DISABLED,
ERROR_CAMERA_DEVICE,
ERROR_CAMERA_SERVICE })
public @interface ErrorCode {};
/**
* The method called when a camera device has finished opening.
*
* <p>At this point, the camera device is ready to use, and
* {@link CameraDevice#createCaptureSession} can be called to set up the first capture
* session.</p>
*
* @param camera the camera device that has become opened
*/
public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
/**
* The method called when a camera device has been closed with
* {@link CameraDevice#close}.
*
* <p>Any attempt to call methods on this CameraDevice in the
* future will throw a {@link IllegalStateException}.</p>
*
* <p>The default implementation of this method does nothing.</p>
*
* @param camera the camera device that has become closed
*/
public void onClosed(@NonNull CameraDevice camera) {
// Default empty implementation
}
/**
* The method called when a camera device is no longer available for
* use.
*
* <p>This callback may be called instead of {@link #onOpened}
* if opening the camera fails.</p>
*
* <p>Any attempt to call methods on this CameraDevice will throw a
* {@link CameraAccessException}. The disconnection could be due to a
* change in security policy or permissions; the physical disconnection
* of a removable camera device; or the camera being needed for a
* higher-priority camera API client.</p>
*
* <p>There may still be capture callbacks that are invoked
* after this method is called, or new image buffers that are delivered
* to active outputs.</p>
*
* <p>The default implementation logs a notice to the system log
* about the disconnection.</p>
*
* <p>You should clean up the camera with {@link CameraDevice#close} after
* this happens, as it is not recoverable until the camera can be opened
* again. For most use cases, this will be when the camera again becomes
* {@link CameraManager.AvailabilityCallback#onCameraAvailable available}.
* </p>
*
* @param camera the device that has been disconnected
*/
public abstract void onDisconnected(@NonNull CameraDevice camera); // Must implement
/**
* The method called when a camera device has encountered a serious error.
*
* <p>This callback may be called instead of {@link #onOpened}
* if opening the camera fails.</p>
*
* <p>This indicates a failure of the camera device or camera service in
* some way. Any attempt to call methods on this CameraDevice in the
* future will throw a {@link CameraAccessException} with the
* {@link CameraAccessException#CAMERA_ERROR CAMERA_ERROR} reason.
* </p>
*
* <p>There may still be capture completion or camera stream callbacks
* that will be called after this error is received.</p>
*
* <p>You should clean up the camera with {@link CameraDevice#close} after
* this happens. Further attempts at recovery are error-code specific.</p>
*
* @param camera The device reporting the error
* @param error The error code.
*
* @see #ERROR_CAMERA_IN_USE
* @see #ERROR_MAX_CAMERAS_IN_USE
* @see #ERROR_CAMERA_DISABLED
* @see #ERROR_CAMERA_DEVICE
* @see #ERROR_CAMERA_SERVICE
*/
public abstract void onError(@NonNull CameraDevice camera,
@ErrorCode int error); // Must implement
}
我們從這個類所定義的方法就能夠非常清楚的看到,它這幾個回調的意圖了:onOpened就是成功打開camera之後的回調,而且它會傳回一個CameraDevice camera對象給我們應用層,基本上操作相機所有重要的工作都是由它來中轉實作的,是以應用層拿到這個對象之後,就可以使用它作很多其他的工作了,在接下來的分析過程中,我們也會看到,這個對象在framework中是怎麼建構好,然後又是怎麼回傳給我們應用層的;onClosed方法就是當相機關閉時的回調了;onDisconnected方法就是相機斷開連接配接時的回調;onError方法就是相機出錯時的回調了。
我們再來看看最後一個參數Handler handler,為什麼要傳一個Handler進來呢?它的目的就是為了保證線程不切換,假如我們在應用層在工作線程B中執行openCamera的方法,同時将線程B對應的Handler對象傳進來,那麼打開成功之後,framework為了保證線程同步,也會使用該handler對象,将消息發送到線程B的Looper循環上,這就是傳入一個Handler對象的原因了,我們在後面的分析過程中會看到它的使用。
好,參數分析完了,我們繼續來看一下openCameraForUid方法的實作,源碼如下:
public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler,
int clientUid)
throws CameraAccessException {
if (cameraId == null) {
throw new IllegalArgumentException("cameraId was null");
} else if (callback == null) {
throw new IllegalArgumentException("callback was null");
} else if (handler == null) {
if (Looper.myLooper() != null) {
handler = new Handler();
} else {
throw new IllegalArgumentException(
"Handler argument is null, but no looper exists in the calling thread");
}
}
openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
}
首先還是參數判斷,我們調用方法時傳入的參數必須合法,否則直接抛出異常,參數合法之後,再調用openCameraDeviceUserAsync來進一步執行camera的打開工作,源碼如下:
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Handler handler, final int uid)
throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
synchronized (mLock) {
ICameraDeviceUser cameraUser = null;
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
handler,
characteristics,
mContext.getApplicationInfo().targetSdkVersion);
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
try {
if (supportsCamera2ApiLocked(cameraId)) {
// Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
}
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), uid);
} else {
// Use legacy camera implementation for HAL1 devices
int id;
try {
id = Integer.parseInt(cameraId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+ cameraId);
}
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
}
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
} else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
// Received one of the known connection errors
// The remote camera device cannot be connected to, so
// set the local camera to the startup error state
deviceImpl.setRemoteFailure(e);
if (e.errorCode == ICameraService.ERROR_DISABLED ||
e.errorCode == ICameraService.ERROR_DISCONNECTED ||
e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
// Per API docs, these failures call onError and throw
throwAsPublicException(e);
}
} else {
// Unexpected failure - rethrow
throwAsPublicException(e);
}
} catch (RemoteException e) {
// Camera service died - act as if it's a CAMERA_DISCONNECTED case
ServiceSpecificException sse = new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
deviceImpl.setRemoteFailure(sse);
throwAsPublicException(sse);
}
// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
// This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
// cameraUser dies during setup.
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
return device;
}
該方法中首先調用getCameraCharacteristics(cameraId)擷取到目标camera的特性參數,這個方法的實作就是在我們前面提到的CameraServer程序當中,因為手機開機時,camera驅動的注冊就開始了,注冊完成之後,所有camera硬體裝置的特性參數都已經儲存在CameraServer程序當中了,我們這裡隻需要擷取就可以了,大家如果想了解,可以繼續往下追查。接下來使用我們傳入的參數構造一個CameraDeviceImpl對象,它其實也就是最終要通過StateCallback回調接口的onOpened方法傳回給我們應用層的那個參數對象了,隻不過這裡剛建構好,它裡邊最核心的一個成員變量還沒有指派,就和Surface一樣,我們雖然可以new Surface創造一個Surface對象,但是它在native層還要執行很多的初始化邏輯,還有它所對應的buffer空間和native層的指針沒有初始化,那麼這個Surface隻是個殼子,沒有什麼實際的用處。我們來看一下frameworks\base\core\java\android\hardware\camera2\impl\CameraDeviceImpl.java類的構造方法,源碼如下:
public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler,
CameraCharacteristics characteristics, int appTargetSdkVersion) {
if (cameraId == null || callback == null || handler == null || characteristics == null) {
throw new IllegalArgumentException("Null argument given");
}
mCameraId = cameraId;
mDeviceCallback = callback;
mDeviceHandler = handler;
mCharacteristics = characteristics;
mAppTargetSdkVersion = appTargetSdkVersion;
final int MAX_TAG_LEN = 23;
String tag = String.format("CameraDevice-JV-%s", mCameraId);
if (tag.length() > MAX_TAG_LEN) {
tag = tag.substring(0, MAX_TAG_LEN);
}
TAG = tag;
Integer partialCount =
mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
if (partialCount == null) {
// 1 means partial result is not supported.
mTotalPartialCount = 1;
} else {
mTotalPartialCount = partialCount;
}
}
這裡比較重要的資訊就是關于tag的指派了,它是執行String.format("CameraDevice-JV-%s", mCameraId)邏輯來指派的,我們也可以在打開相機時搜尋到這個關鍵字,它對我們實際的處理問題可以說是一個點,我們可以從這裡判斷肯定有應用層想要打開相機裝置,而且可以根據id看到想要打開哪個目标裝置。回到openCameraDeviceUserAsync方法中,接下來調用剛才建立好的CameraDeviceImpl對象的getCallbacks()方法擷取一個ICameraDeviceCallbacks對象,它是通過ICameraDeviceCallbacks.aidl定義的,是以它就是一個binder對象,而它的作用就是把這個對象傳遞到CameraServer程序當中,來配合回調各個節點方法的,我們馬上就會看到。接下來判斷if (supportsCamera2ApiLocked(cameraId))條件,它的意思就是目前是否支援camera2.0的協定,這是Android對于相機的優化,我們假設這裡支援,那麼繼續調用cameraUser = cameraService.connectDevice(callbacks, cameraId, mContext.getOpPackageName(), uid)邏輯來給局部變量 cameraUser指派,這句邏輯往下就是我們最核心的地方了,而這個傳回值也就是CameraServer程序派給我們的操作代表,我們應用的各項工作都是由它進行中轉來實作了。
我們繼續往下看完這個方法的實作,然後再回頭來分析cameraService.connectDevice的邏輯實作。接下來最後的兩句就是調用deviceImpl.setRemoteDevice(cameraUser)方法将CameraServer傳回給我們的對象儲存下來,這句邏輯執行完成後,這個deviceImpl才算真正具備功能了,最後就是給局部變量device指派。我們繼續看一下frameworks\base\core\java\android\hardware\camera2\impl\CameraDeviceImpl.java類的setRemoteDevice方法,源碼如下:
public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
synchronized(mInterfaceLock) {
// TODO: Move from decorator to direct binder-mediated exceptions
// If setRemoteFailure already called, do nothing
if (mInError) return;
mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
IBinder remoteDeviceBinder = remoteDevice.asBinder();
// For legacy camera device, remoteDevice is in the same process, and
// asBinder returns NULL.
if (remoteDeviceBinder != null) {
try {
remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
} catch (RemoteException e) {
CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"The camera device has encountered a serious error");
}
}
mDeviceHandler.post(mCallOnOpened);
mDeviceHandler.post(mCallOnUnconfigured);
}
}
這裡會使用CameraServer傳回給我們的 remoteDevice建構一個ICameraDeviceUserWrapper對象,就是将它再包裝一層,然後指派給成員變量mRemoteDevice,我們可以看到,最終我們拿到的那個CameraDevice對象其實離真正給我們幹活的對象已經很遠了,中間都經過了好幾層包裝;然後再調用mDeviceHandler.post(mCallOnOpened)通過應用層,打開相機的工作已經完成了, mDeviceHandler就是我們一開始調用openCamera方法時傳入的第三個參數了,是以使用它來post發送一個消息,那麼回調也會在當時執行openCamera方法的線程上,這樣就可以保證線程不會切換了。mCallOnOpened是CameraDeviceImpl類的一個成員變量,定義源碼如下:
private final Runnable mCallOnOpened = new Runnable() {
@Override
public void run() {
StateCallbackKK sessionCallback = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
sessionCallback = mSessionStateCallback;
}
if (sessionCallback != null) {
sessionCallback.onOpened(CameraDeviceImpl.this);
}
mDeviceCallback.onOpened(CameraDeviceImpl.this);
}
};
這裡的mDeviceCallback成員變量也就是前面構造CameraDeviceImpl對象時傳入的,也就是我們調用openCamera方法的第二個參數了,這時的CameraDeviceImpl對象已經準備好了,于是通過回調接口将CameraDeviceImpl對象傳回給應用層,應用層就可以通過它來執行各種邏輯真正的控制camera了。
好,回調應用層的邏輯分析完,我們回過頭來繼續看一下cameraService.connectDevice方法是如何打開camera的。
cameraService是通過binder程序間通信,執行CameraManagerGlobal.get().getCameraService()擷取到的Camera服務端的一個binder代理對象,它實際的實作是native層的CameraService。CameraServer程序的啟動函數定義在frameworks\av\camera\cameraserver\main_cameraserver.cpp檔案中,它的main函數源碼如下:
using namespace android;
int main(int argc __unused, char** argv __unused)
{
signal(SIGPIPE, SIG_IGN);
// Set 3 threads for HIDL calls
hardware::configureRpcThreadpool(3, /*willjoin*/ false);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
CameraService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
這裡會調用CameraService::instantiate()方法,而 CameraService是繼承了BinderService,是以 instantiate()方法實際也是執行的BinderService對象的instantiate()方法,該方法定義在frameworks\native\libs\binder\include\binder\BinderService.h檔案中,源碼如下:
template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
static void publishAndJoinThreadPool(bool allowIsolated = false) {
publish(allowIsolated);
joinThreadPool();
}
static void instantiate() { publish(); }
static status_t shutdown() { return NO_ERROR; }
private:
static void joinThreadPool() {
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
};
在這裡執行publish方法時,以CameraService類的getServiceName()方法傳回的char*為鍵值(media.camera)将CameraService對象添加到service_manager當中的。是以接下來我們就來看一下CameraService類的connectDevice方法的實作,源碼如下:
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
clientUid, USE_CALLING_PID, API_2,
/*legacyMode*/ false, /*shimUpdateOnly*/ false,
/*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
*device = client;
return ret;
}
這裡的幾個參數我們要看一下,第一個cameraCb就是我們在framework中得到的那個binder對象,以後的部分邏輯都會通過它來進行中轉;cameraId表示我們要打開的目标裝置;clientPackageName表示請求執行打開camera裝置的應用程序包名;clientUid表示應用程序的uid;最後的device就是傳回給framework的對象了,注釋已經寫的非常清楚了,它是一個輸出參數。接下來執行sp<CameraDeviceClient> client = nullptr 聲明一個CameraDeviceClient對象,在給它指派成功之後,将它再指派給輸出參數device,是以說我們在framework中看到的那個cameraUser實際上就是這裡的CameraDeviceClient對象了。
接下來我們繼續分析connectHelper方法的實作,源碼如下:
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
String8 clientName8(clientPackageName);
int originalClientPid = 0;
ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and "
"Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
(halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),
static_cast<int>(effectiveApiLevel));
sp<CLIENT> client = nullptr;
{
// Acquire mServiceLock and prevent other clients from connecting
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
if (lock == nullptr) {
ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting)."
, clientPid);
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
cameraId.string(), clientName8.string(), clientPid);
}
// Enforce client permissions and do basic sanity checks
if(!(ret = validateConnectLocked(cameraId, clientName8,
/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
return ret;
}
// Check the shim parameters after acquiring lock, if they have already been updated and
// we were doing a shim update, return immediately
if (shimUpdateOnly) {
auto cameraState = getCameraState(cameraId);
if (cameraState != nullptr) {
if (!cameraState->getShimParams().isEmpty()) return ret;
}
}
status_t err;
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) {
switch (err) {
case -ENODEV:
return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
"No camera device with ID \"%s\" currently available",
cameraId.string());
case -EBUSY:
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Higher-priority client using camera, ID \"%s\" currently unavailable",
cameraId.string());
default:
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Unexpected error %s (%d) opening camera \"%s\"",
strerror(-err), err, cameraId.string());
}
}
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);
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);
if (facing == -1) {
ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.string());
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Unable to get camera device \"%s\" facing", cameraId.string());
}
sp<BasicClient> tmp = nullptr;
if(!(ret = makeClient(this, cameraCb, clientPackageName, cameraId, 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__);
err = client->initialize(mCameraProviderManager);
if (err != OK) {
ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
// Errors could be from the HAL module open call or from AppOpsManager
switch(err) {
case BAD_VALUE:
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
"Illegal argument to HAL module for camera \"%s\"", cameraId.string());
case -EBUSY:
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Camera \"%s\" is already open", cameraId.string());
case -EUSERS:
return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
"Too many cameras already open, cannot open camera \"%s\"",
cameraId.string());
case PERMISSION_DENIED:
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"No permission to open camera \"%s\"", cameraId.string());
case -EACCES:
return STATUS_ERROR_FMT(ERROR_DISABLED,
"Camera \"%s\" disabled by policy", cameraId.string());
case -ENODEV:
default:
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),
strerror(-err), err);
}
}
// 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;
return ret;
}
該方法是一個模闆方法,這裡的handleEvictionsLocked、client->initialize方法執行出錯之後的日志列印對于我們分析問題也會有非常大的幫助,我們平時工作中經常碰到相機打開失敗的問題,如果有這些日志,那就說明問題肯定是出在CameraServer程序往下哪裡的邏輯中了。
往下我們就主要來看一下makeClient、client->initialize這兩句方法的實作。makeClient方法的源碼如下:
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
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:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),
facing, clientPid, clientUid, getpid(), legacyMode);
} else { // Camera2 API route
ALOGW("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
"Camera device \"%s\" HAL version %d does not support camera2 API",
cameraId.string(), deviceVersion);
}
break;
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),
facing, clientPid, clientUid, servicePid, legacyMode);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
facing, clientPid, clientUid, servicePid);
}
break;
default:
// Should not be reachable
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Camera device \"%s\" has unknown HAL version %d",
cameraId.string(), deviceVersion);
}
} 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.
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),
facing, clientPid, clientUid, servicePid, 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 STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
"Camera device \"%s\" (HAL version %d) cannot be opened as HAL version %d",
cameraId.string(), deviceVersion, halVersion);
}
}
return Status::ok();
}
一般驅動版本halVersion和裝置版本deviceVersion是相同的,是以進入第一個if分支,effectiveApiLevel參數是在調用connectHelper方法時傳入的,值為API_2,是以進入else分支,直接使用我們上邊傳進來的參數構造一個CameraDeviceClient對象,而該對象也就是我們應用程序和CameraServer程序通信的使者了,所有的工作都是由它來進行中轉的。我們繼續看一下它的構造方法的實作。frameworks\av\services\camera\libcameraservice\api2\CameraDeviceClient.cpp類的構造方法源碼如下:
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid) :
Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0) {
ATRACE_CALL();
ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
}
因為它是繼承Camera2ClientBase的,是以也會執行Camera2ClientBase類的構造方法。frameworks\av\services\camera\libcameraservice\common\Camera2ClientBase.cpp類的構造方法的源碼如下:
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid):
TClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
mDeviceActive(false)
{
ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
mDevice = new Camera3Device(cameraId);
LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
在這裡又出現了一個非常重要的對象Camera3Device,後邊我們就會看到,我們操作相機的所有工作在CameraServer程序都是由它中轉來和CameraDaemon程序進行通信的。frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp的構造方法的源碼如下:
Camera3Device::Camera3Device(const String8 &id):
mId(id),
mOperatingMode(NO_MODE),
mIsConstrainedHighSpeedConfiguration(false),
mStatus(STATUS_UNINITIALIZED),
mStatusWaiters(0),
mUsePartialResult(false),
mNumPartialResults(1),
mTimestampOffset(0),
mNextResultFrameNumber(0),
mNextReprocessResultFrameNumber(0),
mNextShutterFrameNumber(0),
mNextReprocessShutterFrameNumber(0),
mListener(NULL),
mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
{
ATRACE_CALL();
camera3_callback_ops::notify = &sNotify;
camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
}
這裡的sProcessCaptureResult是一個函數指針,從它的命名也很容易判斷出來,它就是處理結果回調用,那是哪個結果回調呢?當然是CameraDaemon程序對一幀圖檔處理完成之後的結果回調了,注意這裡的capture不單指拍照,預覽的回調也是通過該接口傳回來進行處理的。
該構造的對象都建立好了,再回到CameraService類的connectHelper方法中,繼續來看一下client->initialize(mCameraProviderManager)邏輯的實作,這裡的client就是CameraDeviceClient了,frameworks\av\services\camera\libcameraservice\api2\CameraDeviceClient.cpp類的 initialize方法的源碼如下:
status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager) {
return initializeImpl(manager);
}
template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr) {
ATRACE_CALL();
status_t res;
res = Camera2ClientBase::initialize(providerPtr);
if (res != OK) {
return res;
}
String8 threadName;
mFrameProcessor = new FrameProcessorBase(mDevice);
threadName = String8::format("CDU-%s-FrameProc", mCameraIdStr.string());
mFrameProcessor->run(threadName.string());
mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this,
/*sendPartials*/true);
return OK;
}
它也是轉調initializeImpl方法來實作的,首先調用Camera2ClientBase::initialize(providerPtr)來執行父類的初始化,然後調用mFrameProcessor = new FrameProcessorBase(mDevice)給成員變量 mFrameProcessor指派,從該成員的命名上就可以看出來,它就是用來處理預覽幀的,它是繼承了Thread類的,我們看到相機的預覽實際就是它在一個無限循環當中不斷的處理request來完成的。frameworks\av\services\camera\libcameraservice\common\FrameProcessorBase.h類的定義源碼如下:
class FrameProcessorBase: public Thread {
public:
explicit FrameProcessorBase(wp<CameraDeviceBase> device);
virtual ~FrameProcessorBase();
struct FilteredListener: virtual public RefBase {
virtual void onResultAvailable(const CaptureResult &result) = 0;
};
// Register a listener for a range of IDs [minId, maxId). Multiple listeners
// can be listening to the same range. Registering the same listener with
// the same range of IDs has no effect.
// sendPartials controls whether partial results will be sent.
status_t registerListener(int32_t minId, int32_t maxId,
const wp<FilteredListener>& listener,
bool sendPartials = true);
status_t removeListener(int32_t minId, int32_t maxId,
const wp<FilteredListener>& listener);
void dump(int fd, const Vector<String16>& args);
protected:
static const nsecs_t kWaitDuration = 10000000; // 10 ms
wp<CameraDeviceBase> mDevice;
virtual bool threadLoop();
Mutex mInputMutex;
Mutex mLastFrameMutex;
struct RangeListener {
int32_t minId;
int32_t maxId;
wp<FilteredListener> listener;
bool sendPartials;
};
List<RangeListener> mRangeListeners;
// Number of partial result the HAL will potentially send.
int32_t mNumPartialResults;
void processNewFrames(const sp<CameraDeviceBase> &device);
virtual bool processSingleFrame(CaptureResult &result,
const sp<CameraDeviceBase> &device);
status_t processListeners(const CaptureResult &result,
const sp<CameraDeviceBase> &device);
CameraMetadata mLastFrame;
};
mFrameProcessor構造好之後,調用mFrameProcessor->run(threadName.string())來啟動它, run方法中的參數就是對目前線程的命名,如果我們碰到相機ANR的問題,也可以通過命名來分析這條線程的邏輯。
最後調用mFrameProcessor->registerListener來注冊回調。第三個參數的定義類型為FilteredListener,實際參數就是目前的CameraDeviceClient對象,FilteredListener也是定義在FrameProcessorBase.h頭檔案中,它隻有一個方法,onResultAvailable,很明顯就是一幀處理好了,需要回調給應用層時,就會通過該方法來完成。
我們接下來在看一下剛才那句Camera2ClientBase::initialize(providerPtr)邏輯,因為它還有很多父類初始化的工作。該方法的源碼如下:
template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager) {
return initializeImpl(manager);
}
template <typename TClientBase>
template <typename TProviderPtr>
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr) {
ATRACE_CALL();
ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
TClientBase::mCameraIdStr.string());
status_t res;
// Verify ops permissions
res = TClientBase::startCameraOps();
if (res != OK) {
return res;
}
if (mDevice == NULL) {
ALOGE("%s: Camera %s: No device connected",
__FUNCTION__, TClientBase::mCameraIdStr.string());
return NO_INIT;
}
res = mDevice->initialize(providerPtr);
if (res != OK) {
ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
__FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
return res;
}
wp<CameraDeviceBase::NotificationListener> weakThis(this);
res = mDevice->setNotifyCallback(weakThis);
return OK;
}
它也是一個模闆方法,範型TProviderPtr就是我們前面從CameraService類中調用過來時傳入的的參數mCameraProviderManager,它的類型為CameraProviderManager。我們一開始說我們可以通過調用CameraManager類的getCameraIdList()方法來擷取到目前已成功注冊的相機裝置的id,那究竟是怎麼擷取到的呢?就是通過CameraProviderManager類中提供的資料來擷取的,因為每一個相機裝置的注冊資訊都會儲存在該類中,是以它知道所有的相機裝置資訊,可以直接傳回給我們。接下來我們繼續分析mDevice->initialize(providerPtr)這句邏輯的實作。這裡的 mDevice就是我們前面初始化好的Camera3Device了,frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp類的initialize方法的源碼如下:
status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
if (mStatus != STATUS_UNINITIALIZED) {
CLOGE("Already initialized!");
return INVALID_OPERATION;
}
if (manager == nullptr) return INVALID_OPERATION;
sp<ICameraDeviceSession> session;
ATRACE_BEGIN("CameraHal::openSession");
status_t res = manager->openSession(mId.string(), this,
/*out*/ &session);
ATRACE_END();
if (res != OK) {
SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
return res;
}
res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
if (res != OK) {
SET_ERR_L("Could not retrive camera characteristics: %s (%d)", strerror(-res), res);
session->close();
return res;
}
std::shared_ptr<RequestMetadataQueue> queue;
auto requestQueueRet = session->getCaptureRequestMetadataQueue(
[&queue](const auto& descriptor) {
queue = std::make_shared<RequestMetadataQueue>(descriptor);
if (!queue->isValid() || queue->availableToWrite() <= 0) {
ALOGE("HAL returns empty request metadata fmq, not use it");
queue = nullptr;
// don't use the queue onwards.
}
});
if (!requestQueueRet.isOk()) {
ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
requestQueueRet.description().c_str());
return DEAD_OBJECT;
}
auto resultQueueRet = session->getCaptureResultMetadataQueue(
[&queue = mResultMetadataQueue](const auto& descriptor) {
queue = std::make_unique<ResultMetadataQueue>(descriptor);
if (!queue->isValid() || queue->availableToWrite() <= 0) {
ALOGE("HAL returns empty result metadata fmq, not use it");
queue = nullptr;
// Don't use the queue onwards.
}
});
if (!resultQueueRet.isOk()) {
ALOGE("Transaction error when getting result metadata queue from camera session: %s",
resultQueueRet.description().c_str());
return DEAD_OBJECT;
}
mInterface = std::make_unique<HalInterface>(session, queue);
std::string providerType;
mVendorTagId = manager->getProviderTagIdLocked(mId.string());
return initializeCommonLocked();
}
這裡有一句非常重要的邏輯status_t res = manager->openSession(mId.string(), this, &session),它會在CameraDaemon程序中執行真正的camera的open過程,同時會傳回一個session對象給我們,前面我們說過,相機核心的事務其中就包括createCaptureSession,當然兩個session不是一個意思,但是這裡openSession的邏輯拿到的東西卻非常重要,這個我們放到以後再說。最後繼續調用initializeCommonLocked完成初始化。initializeCommonLocked方法的源碼如下:
status_t Camera3Device::initializeCommonLocked() {
/** Start up status tracker thread */
mStatusTracker = new StatusTracker(this);
status_t res = mStatusTracker->run(String8::format("C3Dev-%s-Status", mId.string()).string());
if (res != OK) {
SET_ERR_L("Unable to start status tracking thread: %s (%d)",
strerror(-res), res);
mInterface->close();
mStatusTracker.clear();
return res;
}
/** Register in-flight map to the status tracker */
mInFlightStatusId = mStatusTracker->addComponent();
/** Create buffer manager */
mBufferManager = new Camera3BufferManager();
mTagMonitor.initialize(mVendorTagId);
/** Start up request queue thread */
mRequestThread = new RequestThread(this, mStatusTracker, mInterface.get());
res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
if (res != OK) {
SET_ERR_L("Unable to start request queue thread: %s (%d)",
strerror(-res), res);
mInterface->close();
mRequestThread.clear();
return res;
}
mPreparerThread = new PreparerThread();
internalUpdateStatusLocked(STATUS_UNCONFIGURED);
mNextStreamId = 0;
mDummyStreamId = NO_STREAM;
mNeedConfig = true;
mPauseStateNotify = false;
// Measure the clock domain offset between camera and video/hw_composer
camera_metadata_entry timestampSource =
mDeviceInfo.find(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE);
if (timestampSource.count > 0 && timestampSource.data.u8[0] ==
ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
mTimestampOffset = getMonoToBoottimeOffset();
}
// Will the HAL be sending in early partial result metadata?
camera_metadata_entry partialResultsCount =
mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
if (partialResultsCount.count > 0) {
mNumPartialResults = partialResultsCount.data.i32[0];
mUsePartialResult = (mNumPartialResults > 1);
}
camera_metadata_entry configs =
mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
for (uint32_t i = 0; i < configs.count; i += 4) {
if (configs.data.i32[i] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
configs.data.i32[i + 3] ==
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
mSupportedOpaqueInputSizes.add(Size(configs.data.i32[i + 1],
configs.data.i32[i + 2]));
}
}
return OK;
}
這裡又出現了幾個對象:Camera3BufferManager、RequestThread、PreparerThread。Camera3BufferManager是用來管理buffer的, RequestThread是用來處理預覽的request的,PreparerThread是用來作一些準備工作的,大家知道,因為相機預覽是一幀接一幀,不斷的在建立、處理請求,頻率非常高,一般是30fps,當然,比Android的Vsync信号同步的16ms還是要慢,是以這裡開了多條線程用來同時處理不同的工作,以保證相機的效率。
好,到這裡,我們這篇部落格也就介紹完了,現在回頭一想,是不是很奇怪,我們要講的是openCamera的邏輯,但是從頭到尾就隻看到了一些對象的建立,沒有真正的打開相機裝置啊?這也就是我們上面說的status_t res = manager->openSession(mId.string(), this, &session)邏輯的重要性了,真正打開相機的邏輯就是從這裡進去處理的,這個我們放在下一次繼續講,openCamera後續還有很大的一段邏輯要我們分析,完成之後,我們才能大體明白相機到底是怎麼打開的。
西安今天大雪,在家裡手太冷了,好,吃晚飯了,ByeBye!!!