前言

我们首先先看下这个效果是怎么样的,如果有人见过百度音箱或者是小米音箱,就应该对这个会清楚一些,也就是图示中我们是自定义了一个下拉状态栏,并没有使用系统原生的,那么我们就可以根据需求实现我们自定义的下拉状态栏 UI,比如音乐通知,时间、天气显示信息等等。不过这种需要自定义的情况一般是针对于 Android 定制化的地方会用到的多一些,但本文更多的是牵扯的是如何将这个下拉状态栏运行在独立进程中,以及进程之间的通信,这样的话即使下拉状态栏崩溃了,也不会影响主进程。

需求

按照如图示中,我们定义了几个需求如下:

  • 主进程和下拉状态栏进程之间的通信
  • 主进程中可以获取下拉状态栏进程中的状态栏的状态(是否可以下拉,是否完全展开)
  • 在主进程中控制状态栏收起、展开、是否允许下拉控制
  • 在主进程中监听下拉状态栏进程的状态栏收起和展开事件

建立 Binder 连接池

首先这里先回忆一下 AIDL 的使用流程:首先创建一个 Service 和一个 AIDL 接口,接着创建一个类继承自 AIDL 接口中的 Stub 类并实现 Stud 中的抽象方法,在 Service 的 onBind 方法中返回这个类的对象,然后客户端就可以绑定服务端的 Service,建立连接后就可以访问远程服务端的方法了

如果是按照这种使用方式的话,一个 AIDL 的具体的实现类通过一个 Service 在 onBinder 方法中返回给客户端调用,那么如果是存在很多 AIDL 文件的话,那就要创建很多 Service ,并在 onBInder 方法中返回 Binder 对象,显然这样是不合理的。所以我们这里需要引入 Binder 连接池,只维护一个 Service 就可以了,通过 Binder 连接池去查询具体的 Binder 对象,具体连接池的实践可以看这里 Binder 连接池

创建 AIDl 文件

  • 创建 Binder 连接池

    1
    2
    3
    4
    
    interface IBinderPool {
     // 连接池, 根据对应的 code 返回具体的 binder 对象
     IBinder queryBinder( int binderCode);
    }
  • 状态的监听回调

    1
    2
    3
    4
    
    interface IStatusBarCallback {
     void opened();
     void closed();
    }
  • 状态栏的管理

    1
    2
    3
    4
    5
    6
    7
    
    interface IStatusBarManager {
     void open();
     void close();
     void setEnableDropDown(boolean isDropDown);
     void addStatusBarListener(in IStatusBarCallback callback);
     void removeStatusBarListener(in IStatusBarCallback callback);
    }
  • 状态栏状态获取

    1
    2
    3
    4
    5
    6
    
    interface IStatusBarStatus {
    			// 是否可以下拉
    			boolean isDropDown();
    			// 是否完全展开
    	  	boolean isWholeOpened();
    }

创建状态栏进程服务

这里需要建立状态栏进程的服务,然后将 Binder 连接池的 IBinder 对象返回,这样通过连接池就可以获取到其他的 AIDL 具体实现了,然后在我们的服务中开启状态栏,看如下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class StatusBarService : Service() {

    override fun onBind(intent: Intent): IBinder {
        return BinderPool.BinderPoolImpl()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        return START_STICKY
    }

    override fun onCreate() {
        super.onCreate()
				// 开启状态栏 -- 此时这里是状态栏进程中
        val statusBarView = StatusBarView(this)
        StatusBarViewManager.instance.statusBarView = statusBarView
        statusBarView.addToWindow()
    }
}
  • Binder 连接实现类

     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
    
    public static class BinderPoolImpl extends IBinderPool.Stub {
    
        public BinderPoolImpl() {
            super();
        }
    
        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
    
            IBinder iBinder = null;
    
            // 根据code,返回具体的binder对象
            switch (binderCode) {
                case BINDER_MANAGER:
                    iBinder = new StatusBarManagerImpl();
                    break;
    
                case BINDER_STATUS:
                    iBinder = new StatusBarStatusImpl();
                    break;
    
                default:
                    break;
            }
    
    
            return iBinder;
        }
    }

接着看下 StatusBarManagerImpl 和 StatusBarStatusImpl 具体实现类,里面都做了什么

 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
class StatusBarManagerImpl : IStatusBarManager.Stub() {
    companion object {
        private const val TAG = "IStatusBarManagerImpl"
    }

    override fun setEnableDropDown(isDropDown: Boolean) {
        runOnUiThread {
            StatusBarViewManager.instance.statusBarView?.let {
                if (isDropDown) {
                    it.enableStatusBar()
                } else {
                    it.disableStatusBar()
                }
            }
        }
    }

    override fun open() {
        runOnUiThread {
            StatusBarViewManager.instance.statusBarView?.expand()
        }
    }

    override fun addStatusBarListener(callback: IStatusBarCallback?) {
        Log.d(TAG, "addStatusBarListener() isMainThread ${isMainThread()}")
        StatusBarStatusManager.addStatusBarListener(callback)
    }

    override fun removeStatusBarListener(callback: IStatusBarCallback?) {
        StatusBarStatusManager.removeStatusBarListener(callback)
    }

    override fun close() {
        runOnUiThread {
            StatusBarViewManager.instance.statusBarView?.close()
        }
    }
}

可以发现 StatusBarManagerImpl 这个类,主要做了对状态栏是否可以下拉的控制,和状态栏的收起和关闭,设置监听等操作,不过这里需要说明的是,继承自 stub 的类中,都是运行在 Binder 线程池中运行的,也就是非主线程中,要避免调用 UI 等相关操作。

在上述中,我们还调用了一个 StatusBarStatusManager 类,看一下这个类是如何实现的:

 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
object StatusBarStatusManager {

    /**
     *  RemoteCallbackList 保证在多进程中解注册正常
     */
    private val remoteCallbackList by lazy { RemoteCallbackList<IStatusBarCallback>() }

    fun addStatusBarListener(callback: IStatusBarCallback?) {
        remoteCallbackList.register(callback)
    }

    fun removeStatusBarListener(callback: IStatusBarCallback?) {
        remoteCallbackList.unregister(callback)
    }

    fun onClosedCallback() {
        try {
            remoteCallbackList.let { callback ->
                // 遍历的时候,需要配合使用
                val size = callback.beginBroadcast()
                repeat(size) {
                    val broadcastItem = callback.getBroadcastItem(it)
                    // closed 方法也运行在 binder 线程池中,避免 onClosedCallback 方法在主线程调用导致 ANR
                    broadcastItem.closed()
                }
                callback.finishBroadcast()
            }
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    fun onOpenedCallback() {
        try {
            remoteCallbackList.let { callback ->
                // 遍历的时候,需要配合使用
                val size = callback.beginBroadcast()
                repeat(size) {
                    val broadcastItem = callback.getBroadcastItem(it)
                    broadcastItem.opened()
                }
                callback.finishBroadcast()
            }
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }
}

StatusBarStatusManager 这个类中,主要做了往 remoteCallbackList 中注册和解注册的监听,和设置监听回调,remoteCallbackList 是系统专门提供用于删除跨进程 listener 的接口,RemoteCallbackList 是一个泛型,支持管理任意的 Aidl 接口,RemoteCallbackList 的原理是内部有一个 Map 结构专门用来保存所有的 AIDL 回调,这个 Map key 是 IBinder 类型,value 是 CallBack 类型,其中 Callback 中封装了真正远程的 listener ,因为如果使用普通的 ArrayList 来添加 Callback 的话,由于跨进程(序列化和反序列化过程)客户端传输的一个对象会在服务端生成不同的对象,所以如果使用普通的 ArrayList 在注册和解注册的对象都不是同一个了,所以会发现无法解除,但是 RemoteCallbackList 利用的是 IBinder 的唯一对象,在解除注册的时候会查询获取 IBinder 与之相关的 listener 将其移除,并且 RemoteCallbackList 在其遍历的时候,必须的配合一起使用 beginBroadcast 和 finishBroadcast 方法。

解除注册的源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 public boolean unregister(E callback) {
        synchronized (mCallbacks) {
          	// 获取 callback 的 binder 对象,进行移除
            Callback cb = mCallbacks.remove(callback.asBinder());
            if (cb != null) {
                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
                return true;
            }
            return false;
        }
}
1
2
3
4
class StatusBarStatusImpl : IStatusBarStatus.Stub() {
    override fun isDropDown() = StatusBarViewManager.instance.statusBarView?.isDropDown() ?: false
    override fun isWholeOpened()  = StatusBarViewManager.instance.statusBarView?.isWholeOpened() ?: false
}

StatusBarStatusImpl 类会比较简单,主要是做了一些状态栏的状态获取

  • 然后再配置多进程

    1
    2
    3
    4
    5
    6
    
    <application>
        <service
            android:exported="true"
            android:name=".StatusBarService"
            android:process=":statusBar" />
    </application>
  • 提供给外部调用的类,并获取相关的 AIDL 实现类给客户端调用

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    class StatusBarViewManager {
    internal var statusBarView: StatusBarView? = null
    var statusBarManager: IStatusBarManager? = null
    var statusBarStatus: IStatusBarStatus? = null
    
    @WorkerThread
    fun init(context: Context) {
        val binderPool = BinderPool.getInstance(context.applicationContext)
    				// 通过 code 实例不同的 IBinder 对象
        val queryBinder = binderPool.queryBinder(BinderPool.BINDER_MANAGER)
    				// asInterface 返回给客户端调用的 AIDL 对象
        statusBarManager = IStatusBarManager.Stub.asInterface(queryBinder)
    				// asInterface 返回给客户端调用的 AIDL 对象
        statusBarStatus =  				    IStatusBarStatus.Stub.asInterface(binderPool.queryBinder(BinderPool.BINDER_STATUS))
    }
    
    companion object {
        val instance: StatusBarViewManager by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            StatusBarViewManager()
        }
    }
    }

最后使用如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
thread {
 	 		 mStatusBarManager.init(this@MainActivity)
			 mStatusBarManager.statusBarManager?.addStatusBarListener(statusBarListener)
			 mStatusBarManager.statusBarStatus
}

    private val statusBarListener = object : StatusBarCallbackImpl() {
        override fun opened() {
            // 运行在客户端的 binder 线程池中
            Log.d(TAG, "opened() called ${ThreadUtils.isMainThread()}")
        }

        override fun closed() {
            Log.d(TAG, "closed() called ${ThreadUtils.isMainThread()}")
        }
    }

最后相关的多进程通信逻辑就是这些了,感兴趣的话可以看下源码

源码地址:https://github.com/midFang/blogSource/tree/main/ProcessBinderWindow