2.4camera多進程互斥控制

上一節我們提到過handleEvictionsLocked方法是處理相機進程互斥的。這是一個比較重要的方法,隨着現在安卓設備的發力點集中到相機上,同一個應用內的多相機的調用,甚至是不同應用打開不同相機的需求都開始出現,從Framework層面來說就是這裏在進行管理。

根據相機使用的經歷,我們應該有以下幾個經驗

  1. 兩個應用不能同時打開一個camera;
  2. 同一個應用,根據平臺不同(高通、MTK),不一定能同時打開兩個camera;
  3. 分屏模式下兩個應用分別打開不同的相機,哪個應用獲得焦點,那個應用的相機可以活動,另一個無法活動。

造成這些現象的就是handleEvictionsLocked方法。

handleEvictionsLocked方法中的處理邏輯

方法首先判斷API1的情況,前面章節提到過mediaRecoder會產生client需要單獨判斷。如果相機已經打開,就判斷是否是API1並且binder相同,binder相同意味着是同一個進程,那麼久可以正常打開,返回client,否則提示。

接下來獲取所有活動進程的優先級,並將優先級更新到mActiveClientManager中。

mActiveClientManager對象是CameraClientManager類型的,繼承了ClientManager、BasicClient和ClientEventListener,其中BasicClient和ClientEventListener都是CameraService的內部類。

Listener監聽client的add和remove操作。BasicClient定義了CameraClient的一些基本操作,CameraDeviceClientBase類繼承了BasicClient,所以這個類實際上是所有CameraClient的父類。

ClientManager類是對client進行管理的類,內部定義了一個client的描述類ClientDescriptor,包括key(這個key實際上就是camera id,在衝突處理中將全使用key來表示)、value、cost、ownerId、priority和conflicting等屬性。ClientManager類就圍繞被add進來的client進行屬性的get、set等操作。

在更新過優先級之後,就去獲取Camera的狀態,在上一節中已經介紹了CameraState,這裏不再複述。值得一提的是,所有相機的狀態在camera service啓動的時候就已經被獲取了,所以在CameraService中直接調用getCameraState方法就可以得到指定id的狀態。

接下來根據前面兩步獲取到的優先級、CameraState等信息構建clientDescriptor對象。

然後查找與這個clientDescriptor衝突的client,返回的是一個vector隊列。此後方法進入到衝突處理階段。

1.如果衝突的client在這個隊列中,就不能打開相機,給出提示,方法返回。

2. 如果當前client不在evicted衝突隊列中,說明當前應用與其他應用已經打開的相機存在衝突,但是當前相機應用優先級高,cameraservice會將之前被其他應用打開的相機關閉。

最後在衝突處理後,就是mServiceLock.unlock -> evictedClients disconnect -> evictedClients clear ->mServiceLock.lock的操作流程,清空連接,方法返回就不再細述。

ClientManager中的衝突處理邏輯

       在handleEvictionsLocked方法中,我們只是提到了mActiveClientManager.wouldEvict(clientDescriptor)的作用是查找衝突的client,接下來分析是如何查找的。wouldEvict直接調用的wouldEvictLocked方法,所以只要分析這個方法就可以 。

方法首先進行優先級判斷,確定最高優先級的歸屬。

接下來便利所有client,判斷衝突,並添加到衝突list中。判斷條件是1.id相同則衝突,2. isConflicting檢查底層衝突。

如果已經存在較高優先級的client,就把當前client加入到衝突list中,意味着當前client不能打開camera。

如果滿足:

1)存在衝突,且已有client優先級低,

2)不存在衝突,但是totalCost大於maxCost,並且當前client優先級不低於已有client,且當前client與已有client不是同一進程或者爲同一進程但優先級不是最高,

的判斷條件,則將已經存在的client加入到list中,意味着當前client打開時,已存在的client因爲衝突而需要關閉。

最後,判斷當前優先級低,並且底層衝突或者超出了最大cost且當前cost大於0,也加入到list中。

這樣與當前client衝突的就都加入到了list中。

然後判斷當前client自身是否可以打開。

如果當前client優先級不是最高,且超過最大cost,加入到list中,代表當前client不能打開。

至此所有的衝突都已經判斷完畢,並添加到list中返回。

結論

通過上面的分析可以看到衝突的關鍵條件是:

  1. id相同必然衝突;
  2. totalCost超過最大maxCost必然衝突;
  3. 底層衝突(isConflicting爲true)。

 

出現這三種的任意一種都會發生衝突,而決定哪個相機可以打開的決定性條件只有一個:

  1. 優先級,發生衝突優先級低的無法打開。

 

所以反向而言,想要在多進程打開不同相機的前提條件就是:

  1. isConflicting爲false;
  2. tatalCost不大於maxCost;

只要滿足這兩個條件,就能兩個進程同時打開Camera。

發佈了87 篇原創文章 · 獲贊 13 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章