[052]Q平臺(tái)上setBrightness的巨坑

前言

最近解決了一個(gè)掉幀的問題,從應(yīng)用層來看是buffer申請不到,最后發(fā)現(xiàn)是Q平臺(tái)升級+高通的代碼+我們自己驅(qū)動(dòng)優(yōu)化算法導(dǎo)致的计呈,三者缺一不可,由于保密協(xié)議征唬,我只能簡單的原生代碼和簡單的圖來描述這個(gè)問題捌显,避免大家踩坑。

一总寒、Q平臺(tái)上setBrightness的升級

1.1 Android Q

@Override
public void setBrightness(int brightness, int brightnessMode) {
    synchronized (this) {
        // LOW_PERSISTENCE cannot be manually set
        if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
            Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
                    ": brightness=0x" + Integer.toHexString(brightness));
            return;
        }
        // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
        // right now we just fall back to the old path through Lights brightessMode is
        // anything but USER or the device shouldBeInLowPersistenceMode().
        if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
                && mSurfaceControlMaximumBrightness == 255) {
            // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the
            // reason we enforce 255 right now is to stay consistent with the old path. In
            // the future, the framework should be refactored so that brightness is a float
            // between 0.0f and 1.0f, and the actual number of supported brightness levels
            // is determined in the device-specific implementation.
            if (DEBUG) {
                Slog.d(TAG, "Using new setBrightness path!");
            }
            SurfaceControl.setDisplayBrightness(mDisplayToken,
                    (float) brightness / mSurfaceControlMaximumBrightness);
        } else {
            int color = brightness & 0x000000ff;
            color = 0xff000000 | (color << 16) | (color << 8) | color;
            setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
        }
    }
}

1.2 Android P

@Override
public void setBrightness(int brightness, int brightnessMode) {
    synchronized (this) {
        // LOW_PERSISTENCE cannot be manually set
        if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
            Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
                    ": brightness=0x" + Integer.toHexString(brightness));
            return;
        }
        int color = brightness & 0x000000ff;
        color = 0xff000000 | (color << 16) | (color << 8) | color;
        setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
    }
}

1.3 兩者的區(qū)別

we'd like to set the brightness mode through the SF/HWC as well
我們也希望通過SF/HWC設(shè)置屏幕亮度

就是一旦以下條件滿足就會(huì)走Q版本上新的設(shè)置亮度流程

 if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
                && mSurfaceControlMaximumBrightness == 255) 

Android Q上有兩種方式設(shè)置屏幕亮度扶歪,如下圖表示,導(dǎo)致掉幀的就是方式1

方式1:system_server->SF->HWC HAL->設(shè)備節(jié)點(diǎn)->背光驅(qū)動(dòng)(Android Q)
方式2:system_server->Light HAL->設(shè)備節(jié)點(diǎn)->背光驅(qū)動(dòng)(Android Q摄闸, P)

二善镰、為什么會(huì)導(dǎo)致掉幀?

我在前言中已經(jīng)說了是由Q平臺(tái)升級+高通的代碼+我們自己驅(qū)動(dòng)優(yōu)化算法導(dǎo)致的年枕,三者缺一不可炫欺。

2.1 Q平臺(tái)升級

出問題的項(xiàng)目就是走了方式1的流程,所以滿足條件画切。

2.2 高通的代碼

高通的HWC HAL層代碼中對setDisplayBrightness接口實(shí)現(xiàn)中加了一個(gè)display的鎖竣稽。也就意味這HWC其他的接口會(huì)和setDisplayBrightness產(chǎn)生鎖的競爭關(guān)系。

2.3 我們自己驅(qū)動(dòng)優(yōu)化算法

我們在驅(qū)動(dòng)中對背光設(shè)置有一些優(yōu)化霍弹,在特定的情況下毫别,會(huì)導(dǎo)致寫設(shè)備節(jié)點(diǎn)的時(shí)間耗時(shí)200ms左右。

2.4 還原現(xiàn)場

首先lightsensor觸發(fā)了自動(dòng)背光調(diào)節(jié)典格,然后走SF-HWC去設(shè)置了亮度岛宦,持有了display的鎖。

由于驅(qū)動(dòng)的優(yōu)化算法耍缴,導(dǎo)致這把鎖持有了200ms砾肺。

這個(gè)200ms時(shí)間段里,SF繪制每一個(gè)幀的代碼中也有和HWC的調(diào)用防嗡,因?yàn)槟貌坏芥i導(dǎo)致也
block了变汪,從而鎖住了一個(gè)buffer。

應(yīng)用申請一個(gè)buffer蚁趁,完成繪制裙盾,交給sf,sf來不及使用。
應(yīng)用又申請一個(gè)buffer番官,完成繪制庐完,交給sf,sf來不及使用徘熔。
最后應(yīng)用的三個(gè)buffer门躯,一個(gè)處于lock,兩個(gè)處于未用的狀態(tài)(手機(jī)中bufferqueue設(shè)置的是3個(gè))
應(yīng)用再次申請buffer的時(shí)候酷师,沒有可用的buffer了讶凉,導(dǎo)致了主線程的block,最后導(dǎo)致了掉幀的問題的出現(xiàn)山孔。

三缀遍、另外一個(gè)詭異的事情。

雖然問題基本已經(jīng)解決饱须,但是我無法解釋,還有一個(gè)詭異的事情台谊。

同一個(gè)手機(jī)蓉媳,在驅(qū)動(dòng)代碼完全一樣,只不過刷了不同高通基線的代碼
竟然一個(gè)走方式1锅铅,一個(gè)走方式2酪呻。

日志發(fā)現(xiàn)的原因:

方式1的時(shí)候mSurfaceControlMaximumBrightness為255
方式2的時(shí)候mSurfaceControlMaximumBrightness為0

3.1 maximumBrightness為什么是0

基本可以猜到下面的代碼在初始化的時(shí)候有異常,導(dǎo)致了maximumBrightness為0.
為什么會(huì)導(dǎo)致maximumBrightness為0盐须,簡單的說一下就是高通的基線升級導(dǎo)致了getDisplayBrightnessSupport返回了true玩荠,我就不展開講了。

private LightImpl(Context context, int id) {
    mId = id;
    mDisplayToken = SurfaceControl.getInternalDisplayToken();
    final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport(
            mDisplayToken);
    if (DEBUG) {
        Slog.d(TAG, "Display brightness support: " + brightnessSupport);
    }
    int maximumBrightness = 0;
    if (brightnessSupport) {
        PowerManager pm = context.getSystemService(PowerManager.class);
        if (pm != null) {
            maximumBrightness = pm.getMaximumScreenBrightnessSetting();
        }
    }
    mSurfaceControlMaximumBrightness = maximumBrightness;
}

3.2 負(fù)負(fù)得正

這個(gè)就是典型的負(fù)負(fù)得正贼邓,基線沒有升級導(dǎo)致了getDisplayBrightnessSupport為false阶冈,導(dǎo)致了mSurfaceControlMaximumBrightness為0,最后走方式2塑径,掉幀問題也就消失女坑。

總結(jié)

基本上整個(gè)問題的分析過程,我是通過trace分析出來的统舀,然后結(jié)合特定關(guān)鍵點(diǎn)的log匆骗,把這個(gè)問題給解決了。這是一個(gè)很有意思的問題誉简,不方便放trace的截圖碉就,無法和大家分享如何看trace。

但是除了學(xué)會(huì)看trace的技巧闷串,你一定要清楚的知道每一個(gè)進(jìn)程瓮钥,每一個(gè)線程之前的通信的關(guān)系,然后在自己的腦海中去還原現(xiàn)場,抽絲剝繭骏庸,找到問題點(diǎn)毛甲。

整個(gè)問題牽涉到APP-Framework-Kernel,如果你想要在性能優(yōu)化上更近一步具被,我個(gè)人認(rèn)為打通APP-Framework-Kernel是非常重要的一步玻募。

尾巴

為什么Android Q上要大費(fèi)周章通過SF/HWC去設(shè)置屏幕亮度,我推測是谷歌希望將屏幕亮度調(diào)節(jié)和屏幕UI顯示之間建立起一個(gè)關(guān)系一姿,一起配合調(diào)整七咧,讓用戶對屏幕的觀感效果更好。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叮叹,一起剝皮案震驚了整個(gè)濱河市艾栋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛉顽,老刑警劉巖蝗砾,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異携冤,居然都是意外死亡悼粮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門曾棕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扣猫,“玉大人,你說我怎么就攤上這事翘地∩暧龋” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵衙耕,是天一觀的道長昧穿。 經(jīng)常有香客問我,道長橙喘,這世上最難降的妖魔是什么粤咪? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮渴杆,結(jié)果婚禮上寥枝,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布兔港。 她就那樣靜靜地躺著,像睡著了一般冠跷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天蜜托,我揣著相機(jī)與錄音抄囚,去河邊找鬼。 笑死橄务,一個(gè)胖子當(dāng)著我的面吹牛幔托,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜂挪,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼重挑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了棠涮?” 一聲冷哼從身側(cè)響起谬哀,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎严肪,沒想到半個(gè)月后史煎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驳糯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年劲室,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片结窘。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖充蓝,靈堂內(nèi)的尸體忽然破棺而出隧枫,到底是詐尸還是另有隱情,我是刑警寧澤谓苟,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布官脓,位于F島的核電站,受9級特大地震影響涝焙,放射性物質(zhì)發(fā)生泄漏卑笨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一仑撞、第九天 我趴在偏房一處隱蔽的房頂上張望赤兴。 院中可真熱鬧,春花似錦隧哮、人聲如沸桶良。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陨帆。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疲牵,已是汗流浹背承二。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纲爸,地道東北人亥鸠。 一個(gè)月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像缩焦,于是被迫代替她去往敵國和親读虏。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容