Android 7.0 Brightness亮度调节流程分析

Posted by Bill on October 16, 2018

1. 背景

Android 7.0 盒子需要支持双屏同时输出,通过HDMI的显示器不支持亮度调节,而LCD输出需要支持亮度调节,因此有了解亮度调节是如何进行调节的需求。负责显示的同事经过交流后,提供了一系列节点,”你只需要把这些节点按照这个顺序写就好了啊”。但是作为系统工作者,自然不能随便将写节点的操作放在上层,需要弄清楚整条通路后,再分析哪里是最佳的实现点。

接下来的分析涉及的文件包括:

  • frameworks/base/services/java/com/android/server/SystemServer.java
  • frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
  • frameworks/base/services/core/java/com/android/server/SystemService.java
  • frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
  • frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
  • frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
  • frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp

2. FrameWork调节亮度流程

Framework的整个流程如下图所示:

2.1 亮度相关Service启动流程

为了要支持亮度调节,需要Android系统的两大服务PMS(PowerManagerService)以及DMS(DisplayManagerService)的支持,它们的启动均在SystemServer启动的流程时开始。而SystemServer为了能够开启这两大服务,需要借助SystemServiceManager的协助。可以看到SystemServer在开启服务的时候都用了类似如下语句:

1
2
3
4
5
6
7
//SystemServer
private PowerManagerService mPowerManagerService;
private DisplayManagerService mDisplayManagerService;
....
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
....
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

这里有几个巧妙的设计,一是所有服务,都继承了SystemService父类,二是SystemServiceManager通过获取服务名,利用反射最终调用到服务的onStart方法,从而运行服务,所以每个服务观察也可以看出基本实现了onStart这个接口。startService的关键代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//SystemServiceManager
public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            // Create the service.
            ......
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } catch (...) {
            ...//捕获相关异常,包括InstantiationException,
               //IllegalAccessException,NoSuchMethodException,InvocationTargetException 
            } 

            //SystemService维护着一个链表用以保存所有的服务
            mServices.add(service);

            // Start it.
            try {
                service.onStart();
            } catch (RuntimeException ex) {
                ...
            }
            return service;
        } finally {
            ...
        }
    }

当DMS被调用后,调用onStart方法,其实现如下:

1
2
3
4
5
6
7
8
//DisplayManagerService
@Override
    public void onStart() {
        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
        publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
                true /*allowIsolated*/);
        publishLocalService(DisplayManagerInternal.class, new LocalService());
    }
  • 首先MDS发送MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER到DisplayManagerHandelr处理,并最终调用到方法registerDefaultDisplayAdapter(),用于注册一个displayAdapter,其中DisplayAdapterListener将会监听DisplayDevice的变化,一旦有增删修改等,就会通知到DMS进行处理。
  • DMS还实现两个重要的内部类,LocalService,继承DisplayManagerInternal,另一个是BinderService,继承IDisplayManager.Stub。
  • publishBinderService的意图在于能够让其他服务能够通过binder通信与DMS进行通信(publish即公开,公开这个Binder服务),而其实现也可以看出来是将这个BinderService加入到服务台ServiceManager中,以后通过名字即可以找到该binderService,并最终调用到DMS的方法中。
1
2
3
4
5
//SystemService
protected final void publishBinderService(String name, IBinder service,
        boolean allowIsolated) {
    ServiceManager.addService(name, service, allowIsolated);
}

从这个角度看,BinderService是为了能够让DMS的功能能够通过ServiceManager进行查询并调用,也算是Adapter的用法了。

  • publishLocalService的用法与publishBinderService的用法类似,区别是后者是专门注册Binder服务,而前者是注册的本地服务,源码有一段这样的话表明了其设计的用意:
1
2
 * This class is used in a similar way as ServiceManager, except the services registered here
 * are not Binder objects and are only available in the same process.

即在同一个进程的服务,可轻松的调用其他服务的LocalService,由此也引出了PMS是如何调用DMS的本地服务的:

1
2
3
4
5
6
7
8
9
10
11
./services/core/java/com/android/server/power/PowerManagerService.java
//PowerManagerService
public void systemReady(IAppOpsService appOps) {
    synchronized (mLock) {
        mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
        ....
        // Initialize display power management.
        mDisplayManagerInternal.initPowerManagement(
                mDisplayPowerCallbacks, mHandler, sensorManager);
...
}

2.2 BrightnessDialog调用流程

从UI角度看,亮度调节主要涉及BrightnessDialog,BrightnessController,BrightnessObserver。其中:

  • BrightnessDialog主要负责UI显示,创建BrightnessController
  • BrightnessController用于实际控制亮度,根据ToogleSlider的位置设置值调节亮度
  • BrightnessObserver用于观测ToggleSlider的变化,并及时反映给BrightnessController

亮度调节一般可以通过Settings进行调用,其中Settings的display_settings布局文件有定义:

1
2
3
4
5
6
7
//Settings
<PreferenceScreen
        android:key="brightness"
        android:title="@string/brightness"
        settings:keywords="@string/keywords_display_brightness_level">
    <intent android:action="android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
</PreferenceScreen> 

PreferenceScreen指定intent,在选中的时候即可以发送android.intent.action.SHOW_BRIGHTNESS_DIALOG开启Activity,framework中首先用AndroidManifest定义了该Activity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//frameworks/base/packages/SystemUI/AndroidManifest.xml
<activity
  android:name=".settings.BrightnessDialog"
  android:label="@string/quick_settings_brightness_dialog_title"
  android:theme="@android:style/Theme.DeviceDefault.Dialog"
  android:finishOnCloseSystemDialogs="true"
  android:launchMode="singleInstance"
  android:excludeFromRecents="true"
  android:exported="true">
  <intent-filter>
      <action android:name="android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
      <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

2.2.1 BrightnessDialog

BrightnessDialog(后简述为BD)的功能较简单,在创建的时候初始化了BrightnessController:

1
2
3
4
5
6
7
8
9
10
//BrightnessDialog
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...//Ui initial
        final ImageView icon = (ImageView) findViewById(R.id.brightness_icon);
        final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider);
        mBrightnessController = new BrightnessController(this, icon, slider);//BC与ToggleSlider绑定起来。
    }

并在onStart,onStop分别调用如下方法,注册相应的回调函数。

1
2
mBrightnessController.registerCallbacks();
mBrightnessController.unregisterCallbacks();

2.2.2 BrightnessController && BrightnessObserver

BrightnessController正如其名(后简述为BC),是用于控制亮度的核心,它在UI(BD)创建的时候被new。BC在创建的时候,会新建BrightnessObserver(后简述为BO),并在上述BD调用registerCallbacks,unregisterCallbacks中,分别调用startObserving以及stopObserving,用以检测系统亮度属性的变化。此后有两种方式改变亮度:

  1. 通过直接拉动ToggleSlider改变亮度值。
  2. 通过修改系统亮度属性改变亮度值。

由于BC继承了ToggleSlider.Listener的接口,方法1在用户拉动度条的同时,ToggleSlider会调用onChanged回调方法,由此会调用到BC的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//BrightnessController
@Override
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
        boolean stopTracking) {
    updateIcon(mAutomatic);
    if (mExternalChange) return;

    if (!mAutomatic) {
        final int val = value + mMinimumBacklight;
        ....
        setBrightness(val);//设置亮度
        if (!tracking) {
            //将该值存储到数据库中
            AsyncTask.execute(new Runnable() {
                    public void run() {
                        Settings.System.putIntForUser(mContext.getContentResolver(),
                                Settings.System.SCREEN_BRIGHTNESS, val,
                                UserHandle.USER_CURRENT);
                    }
                });
        }
    } else {
        //自动调节亮度,暂不分析
    }

    for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
        cb.onBrightnessLevelChanged();
    }
}

方法2如果修改系统属性,由于BO监听了亮度有关的值,当发生改变时,会通过其BO的onChange方法进行反馈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//BrightnessObserver
public void startObserving() {
            final ContentResolver cr = mContext.getContentResolver();
            cr.unregisterContentObserver(this);
            cr.registerContentObserver(
                    BRIGHTNESS_MODE_URI,
                    false, this, UserHandle.USER_ALL);
            cr.registerContentObserver(
                    BRIGHTNESS_URI,
                    false, this, UserHandle.USER_ALL);
            cr.registerContentObserver(
                    BRIGHTNESS_ADJ_URI,
                    false, this, UserHandle.USER_ALL);
        }
...

@Override
public void onChange(boolean selfChange, Uri uri) {
    if (selfChange) return;
    try {
        mExternalChange = true;
        if (BRIGHTNESS_MODE_URI.equals(uri)) {
            updateMode();//修改亮度模式
            updateSlider();//一旦发生改变,updateSlider通过获取亮度的修改值,并反馈到进度条中
        } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
            updateSlider();
        } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
            updateSlider();
        } else {
            updateMode();
            updateSlider();
        }
        for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
            cb.onBrightnessLevelChanged();
        }
    } finally {
        mExternalChange = false;
    }
}

至此,BrightnessDialog的分析告一段落,接下来可以分析setBrightness的流程。

3.Brightness && PowermanagerService

3.1 IPowerManager的Binder设计

  • frameworks/base/core/java/android/os/IPowerManager.aidl

Brightness将首先与PMS发生联系,其流程图调用如下,其中由左至右,分别为IPowerManager.stub.proxy, IPowerManager.stub以及PMS

可追溯到BC的setBrightness方法,开篇即通过经典的IPowerManager.Stub(服务端)的asInterface方法获取proxy端,以后需要调用PMS服务时,即通过proxy端通过binder与服务端进行进程间通信。

1
2
3
4
5
6
7
8
9
10
//BrightnessController
private final IPowerManager mPower;
mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));

private void setBrightness(int brightness) {
    try {
        mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
    } catch (RemoteException ex) {
    }
}

感兴趣的还可以找到其IPowerManager.aidl以及编译出来的IPowerManager来对比:

1
2
3
4
5
//IPowerManager.aidl
interface IPowerManager
{
void setTemporaryScreenBrightnessSettingOverride(int brightness);
}

通过编译后,在out下生成对应的IPowerManager.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/IPowerManager.java

//asInterface
public static android.os.IPowerManager asInterface(android.os.IBinder obj)
{
    if ((obj==null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof android.os.IPowerManager))) {
        return ((android.os.IPowerManager)iin);
    }
    //返回的是Stub内部类Proxy代理端
    return new android.os.IPowerManager.Stub.Proxy(obj);
}
...

private static class Proxy implements android.os.IPowerManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
...
}

其中Proxy的参数obj对应mRemote,指向的是服务端的对象,例如本例中调用setTemporaryScreenBrightnessSettingOverride时,生成对应的proxy方法为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//IPowerManager.Stub.Proxy
@Override public void setTemporaryScreenBrightnessSettingOverride(int brightness) throws android.os.RemoteException
{
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeInt(brightness);
        mRemote.transact(Stub.TRANSACTION_setTemporaryScreenBrightnessSettingOverride, _data, _reply, 0);
        _reply.readException();
    }
    finally {
        _reply.recycle();
        _data.recycle();
    }
}

通过aid生成的proxy方法基本都是相同的,其中_data,_reply均从Parcel池中获取,_data都要首先写入一个DESCRIPTOR,一般是包名,再顺序把输入参数写入,最终调用核心部分mRemote的方法transact,其实即服务端的方法。一般每个方法都对应一个int值,其定义在Stub中如下:

1
2
3
4
5
//IPowerManager.Stub
static final int TRANSACTION_acquireWakeLock = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_acquireWakeLockWithUid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
....
static final int TRANSACTION_setTemporaryScreenBrightnessSettingOverride = (android.os.IBinder.FIRST_CALL_TRANSACTION + 23);

通过这些数值,proxy端和服务端就可以在transact的时候分清到底需要调用什么方法。再经过一系列从java到Native,到驱动,最后到服务进程中的onTransact方法,用户只需要在子类实现onTransact即可,父类已经通过aidl自动生成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//IPowerManager.Stub onTransact()
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
...
case TRANSACTION_setTemporaryScreenBrightnessSettingOverride:
{
    data.enforceInterface(DESCRIPTOR);
    int _arg0;
    _arg0 = data.readInt();
    this.setTemporaryScreenBrightnessSettingOverride(_arg0);//子类需要实现该方法
    reply.writeNoException();
    return true;
}
...
}

而其子类正是之前提及的BinderService,作为PMS的内部类,最终调用到PMS的方法:

1
    private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness);

3.2 PMS的亮度控制

PMS的调用流程图如下:

让我有疑问的是,为什么对于亮度的调节需要经过PMS的控制,如果直接经过DMS不是方便得多么?而在updatePowerStateLocked似乎解答了这个问题,其基本实现如下几个步骤:

  1. Phase 0: Basic state updates.
  2. Phase 1: Update wakefulness.
  3. Phase 2: Update display power state.
  4. Phase 3: Update dream state (depends on display ready signal).
  5. Phase 4: Send notifications, if needed.
  6. Phase 5: Update suspend blocker.

其中Phase 2的目的即调用DMS来调节亮度,而除了亮度调节,还需要先判断Battery的状态,系统是否休眠,是否处于屏保模式等内容,都需要PMS进行处理,并最终调用到updateDisplayPowerStateLocked方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//PowerManagerService
private boolean updateDisplayPowerStateLocked(int dirty) {
        final boolean oldDisplayReady = mDisplayReady;
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
            //获取显示策略
            mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();

            // Determine appropriate screen brightness and auto-brightness adjustments.
            boolean brightnessSetByUser = true;
            int screenBrightness = mScreenBrightnessSettingDefault;
            boolean autoBrightness = (mScreenBrightnessModeSetting ==
                    Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
            if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                screenBrightness = mScreenBrightnessOverrideFromWindowManager;
                autoBrightness = false;
                brightnessSetByUser = false;
            } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
                screenBrightness = mTemporaryScreenBrightnessSettingOverride;
            } else if (isValidBrightness(mScreenBrightnessSetting)) {
                screenBrightness = mScreenBrightnessSetting;
            }
            if (autoBrightness) {
                //自动调节亮度相关
            }
            screenBrightness = Math.max(Math.min(screenBrightness,
                    mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
            ....
            // Update display power request.
            mDisplayPowerRequest.screenBrightness = screenBrightness;
            ...
            mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
            mDisplayPowerRequest.useAutoBrightness = autoBrightness;
            mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
            mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
            mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress;
            mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;

            if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
                if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
                        && (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
                    mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
                }
                mDisplayPowerRequest.dozeScreenBrightness =
                        mDozeScreenBrightnessOverrideFromDreamManager;
            } else {
                mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
                mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
            }
            //调用到mDisplayManagerInternal实现亮度调节
            mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                    mRequestWaitForNegativeProximity);
            mRequestWaitForNegativeProximity = false;

        }
        return mDisplayReady && !oldDisplayReady;
    }

以上代码可得,PMS包装了一个DisplayPowerRequest类,并将其传递给DisplayManagerInternal,而该类用以形容电源属性(Power State),诸如屏幕是否关闭,屏幕亮度的状态等。至于DisplayManagerInternal实例,则是调用了DMS的LocalServices,毕竟PMS和DMS都属于同一个进程,不需要进行Binder通信!

1
    mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);

3.3 DMS的亮度控制

DMS的流程是亮度控制的核心,分别对应的类为:

承接上述分析,一切的来源均来自于PMS调用了DMS的本地服务:

事实上,DMS localService在PMS调用时,调用了initPowerMangement方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
        SensorManager sensorManager) {
    synchronized (mSyncRoot) {
        //新建了DisplyBlanker对象,该对象似乎只是作为一个接口类,
        //调用到DMS的方法requestGlobalDisplayStateInternal
        DisplayBlanker blanker = new DisplayBlanker() {
            @Override
            public void requestDisplayState(int state, int brightness) {
                // The order of operations is important for legacy reasons.
                if (state == Display.STATE_OFF) {
                    requestGlobalDisplayStateInternal(state, brightness);
                }

                callbacks.onDisplayStateChange(state);

                if (state != Display.STATE_OFF) {
                    requestGlobalDisplayStateInternal(state, brightness);
                }
            }
        };
        mDisplayPowerController = new DisplayPowerController(
                mContext, callbacks, handler, sensorManager, blanker);
    }
}
1
2
3
4
5
6
//DisplayManagerService LocalService
@Override
public boolean requestPowerState(DisplayPowerRequest request,
    boolean waitForNegativeProximity) {
    return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity);
}

而从流程图可得,DPC(DisplayPowerController)通过Handler发送消息到DisplayControllerHandler中处理。至于为什么需要使用Handler来处理,可能是该方法耗时较久,需要另外的线程去更新状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//DisplayPowerController

private void updatePowerState() {
...

//初次需要初始化
if (mustInitialize) {
    initialize();
}

int brightness = PowerManager.BRIGHTNESS_DEFAULT;
...//忽略了大量对brightness的赋值,只关注手动赋值
if (brightness < 0) {
    brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
}


if (!mPendingScreenOff) {
    if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
        //设置亮度
        animateScreenBrightness(brightness,
        slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : mBrightnessRampRateFast);
    } else {
        animateScreenBrightness(brightness, 0);
    }
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//DisplayPowerController

private void initialize() {
    ...
    mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
            mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
    mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
    ...
}

private void animateScreenBrightness(int target, int rate) {
   if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
       try {
           mBatteryStats.noteScreenBrightness(target);
       } catch (RemoteException ex) {
           // same process
       }
   }

至此ScreenBrightnessRampAnimator调用时,传入了DisplayPowerState.SCREEN_BRIGHTNESS,当调用animateTo时,将会调用到Property的setValue方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//DisplayPowerState

public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
        new IntProperty<DisplayPowerState>("screenBrightness") {
    @Override
    public void setValue(DisplayPowerState object, int value) {
        object.setScreenBrightness(value);
    }

    @Override
    public Integer get(DisplayPowerState object) {
        return object.getScreenBrightness();
    }
};


public void setScreenBrightness(int brightness) {
    if (mScreenBrightness != brightness) {
        mScreenBrightness = brightness;
        if (mScreenState != Display.STATE_OFF) {
            mScreenReady = false;
            scheduleScreenUpdate();
        }
    }
}

scheduleScreenUpdate会利用Handler发送一个Runnable对象,并实现了其中的run方法,其中涉及PhotonicModulator对象,该对象在DisplyPowerState初始化时,即作为独立线程开始运行,而这个线程的日常,貌似就是等待状态的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//DisplayPowerState
private final Runnable mScreenUpdateRunnable = new Runnable() {
   @Override
   public void run() {
       mScreenUpdatePending = false;

       int brightness = mScreenState != Display.STATE_OFF
               && mColorFadeLevel > 0f ? mScreenBrightness : 0;
       if (mPhotonicModulator.setState(mScreenState, brightness)) {
           if (DEBUG) {
               Slog.d(TAG, "Screen ready");
           }
           mScreenReady = true;
           invokeCleanListenerIfNeeded();
       } else {
           if (DEBUG) {
               Slog.d(TAG, "Screen not ready");
           }
       }
   }
;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//PhotonicModulator
private final class PhotonicModulator extends Thread {

    public boolean setState(int state, int backlight) {
            synchronized (mLock) {
                boolean stateChanged = state != mPendingState;
                boolean backlightChanged = backlight != mPendingBacklight;
                if (stateChanged || backlightChanged) {
                    mPendingState = state;
                    //该值即亮度
                    mPendingBacklight = backlight;

                    boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
                    mStateChangeInProgress = stateChanged;
                    mBacklightChangeInProgress = backlightChanged;

                    if (!changeInProgress) {
                        //唤醒该Lock
                        mLock.notifyAll();
                    }
                }
                return !mStateChangeInProgress;
            }
        }
}

@Override
public void run() {
    for (;;) {
        // Get pending change.
        final int state;
        final boolean stateChanged;
        final int backlight;
        final boolean backlightChanged;
        //当setvalue调用后,notifyAll后,运行以下逻辑
        synchronized (mLock) {
            state = mPendingState;
            stateChanged = (state != mActualState);
            //亮度值
            backlight = mPendingBacklight;
            backlightChanged = (backlight != mActualBacklight);
            if (!stateChanged) {
                // State changed applied, notify outer class.
                postScreenUpdateThreadSafe();
                mStateChangeInProgress = false;
            }
            if (!backlightChanged) {
                mBacklightChangeInProgress = false;
            }
            if (!stateChanged && !backlightChanged) {
                try {
                    mLock.wait();
                } catch (InterruptedException ex) { }
                continue;
            }
            mActualState = state;
            mActualBacklight = backlight;
        }
        //设置亮度,调用到DMS的方法
        mBlanker.requestDisplayState(state, backlight);
    }
} 

如此反反复复,最终总算回到DMS中了,最终DMS会遍历检查所有DisplayDevice,并将可用的加入workQueue中。并调用每个显示设备的requestDisplayStateLocked。

1
2
3
4
5
6
7
8
9
10
11
//DisplayManagerService
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
    final int count = mDisplayDevices.size();
    for (int i = 0; i < count; i++) {
        DisplayDevice device = mDisplayDevices.get(i);
        Runnable runnable = updateDisplayStateLocked(device);
        if (runnable != null) {
            workQueue.add(runnable);
        }
    }
}

每个显示设备到最后,会借助到LightImpl的方法,setBrightness来实现亮度的调节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//LocalDisplayAdapter
private final class LocalDisplayDevice extends DisplayDevice {
    private final Light mBacklight;
    ...
    //LightService
    LightsManager lights = LocalServices.getService(LightsManager.class);
    mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
}

private void setDisplayBrightness(int brightness) {
    try {
        mBacklight.setBrightness(brightness);
    } finally {
        ...
    }
}

3.5 LightImpl

  • frameworks/base/services/core/java/com/android/server/lights/LightsService.java

回到SystemServer,在其启动时,还会调用关于Light的服务:

1
2
    mSystemServiceManager.startService(LightsService.class);

在Light启动时,首先初始化Native层逻辑,并在onStart时,向外暴露除了接口,和SystemServer同一个进程的其他服务就可以通过LocalService去获取相关的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//LightsService
public LightsService(Context context) {
    super(context);
    
    mNativePointer = init_native();
    
    for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
        mLights[i] = new LightImpl(i);
    }
}

@Override
public void onStart() {
    publishLocalService(LightsManager.class, mService);
}

private final LightsManager mService = new LightsManager() {
   @Override
   //DMS可以通过getLight获取LightImpl对象
   public Light getLight(int id) {
       if (id < LIGHT_ID_COUNT) {
           return mLights[id];
       } else {
           return null;
       }
   }
};

至此,当DMS调用mBacklight.setBrightness(brightness)设置亮度时,将会调用如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
LightsService LightImpl

@Override
public void setBrightness(int brightness, int brightnessMode) {
    synchronized (this) {
        //将亮度转化为RGB
        int color = brightness & 0x000000ff;
        color = 0xff000000 | (color << 16) | (color << 8) | color;
        setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
    }
}

private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
    if (!mLocked && (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS ||
            mBrightnessMode != brightnessMode)) {
        mLastColor = mColor;
        mColor = color;
        mMode = mode;
        mOnMS = onMS;
        mOffMS = offMS;
        mLastBrightnessMode = mBrightnessMode;
        mBrightnessMode = brightnessMode;
        try {
            //调用Native层设置亮度
            setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
        } finally {
            ...
        }
    }
}

3.6 Lights的Native实现

  • frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
        jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
{
    Devices* devices = (Devices*)ptr;
    light_state_t state;

    if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
        return ;
    }

    uint32_t version = devices->lights[light]->common.version;

    memset(&state, 0, sizeof(light_state_t));

    if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
        if (light != LIGHT_INDEX_BACKLIGHT) {
            ALOGE("Cannot set low-persistence mode for non-backlight device.");
            return;
        }
        if (version < LIGHTS_DEVICE_API_VERSION_2_0) {
            // HAL impl has not been upgraded to support this.
            return;
        }
    } else {
        // Only set non-brightness settings when not in low-persistence mode
        state.color = colorARGB;
        state.flashMode = flashMode;
        state.flashOnMS = onMS;
        state.flashOffMS = offMS;
    }

    state.brightnessMode = brightnessMode;

    {
        ALOGD_IF_SLOW(50, "Excessive delay setting light");
        //设置亮度
        devices->lights[light]->set_light(devices->lights[light], &state);
    }
}

分析了Native层后,也不适宜直接加入亮度调节的逻辑,需要往下分析Hal层的逻辑。

3.7 Lights的Hal层分析

在本地方案搜了个遍,居然没有发现set_light的实现,那么就可能是hal层没有提供相应的支持。搜了下其他方案,其实都有相关的实现,正可以借助其他方案,如华为,高通的实现,去适配本平台的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Android.mk

LOCAL_PATH:= $(call my-dir)
# HAL module implemenation stored in
# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so
include $(CLEAR_VARS)

LOCAL_SRC_FILES := lights.c
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"xxxxlights\"
LOCAL_MODULE := lights.xxxx//xxx为方案
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)

由此可得,Hal层将会编译出light.[平台].so的库,提供给Native层。在HAL层,只需要实现set_light_backlight方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//lights.c
static struct hw_module_methods_t lights_module_methods = {
    .open =  open_lights,
};

/*
 * The lights Module
 */
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = LIGHTS_HARDWARE_MODULE_ID,
    .name = "lights Module",
    .author = "Google, Inc.",
    .methods = &lights_module_methods,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
static int open_lights(const struct hw_module_t* module, char const* name,
        struct hw_device_t** device)
{
    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);

    if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
        set_light = set_light_backlight;
    else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
        set_light = set_light_notifications;
    else
        return -EINVAL;

    pthread_once(&g_init, init_globals);

    struct light_device_t *dev = malloc(sizeof(struct light_device_t));

    if(!dev)
        return -ENOMEM;

    memset(dev, 0, sizeof(*dev));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0;
    dev->common.module = (struct hw_module_t*)module;
    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
    dev->set_light = set_light;

    *device = (struct hw_device_t*)dev;
    return 0;
}


static int
set_light_backlight(struct light_device_t* dev,
        struct light_state_t const* state)
{
    int err = 0;
    int brightness = rgb_to_brightness(state);
    if(!dev) {
        return -1;
    }
    pthread_mutex_lock(&g_lock);
    //打开相应的节点
    int dispfd = open(DISPLAY_DEV_PATH, O_RDWR);
    if(dispfd >= 0){
        //...进行显示同事的操作即可。。。 
        close(dispfd);
    }
    else{
        ...
    }
    pthread_mutex_unlock(&g_lock);
    return err;
}

至此,完成了亮度调节功能的实现,中间的过程其实十分复杂,但对于平台厂商,一般都在Hal层实现,以后需要实现类似的功能,可以快速跳过FrameWork的流程,只直接看Hal逻辑即可。