AndroidQ SystemUI之插件化机制Plugin

这篇文章接着上一篇SystemUI之启动未分析完的SystemUI插件化机制相关的代码

SystemUI插件

SystemUI插件提供了一种快速创建SystemUI功能原型的简便方法,可以在运行时更改SystemUI的行为。 通过创建插件实现SysUI中使用的一组基本接口来完成,然后可以比当前更快的速度迭代由该接口控制的部分代码。

简单来说就是可以快速替换SystemUI原有的组件,也叫hook,我们就来分析下其中的原理

SystemUIApplication.startServicesIfNeeded

private void startServicesIfNeeded(String[] services) {
		//省略上一篇文章分析过的代码
        	.....
        Dependency.get(InitController.class).executePostInitTasks();
        log.traceEnd();
        final Handler mainHandler = new Handler(Looper.getMainLooper());
        //调用addPluginListener传入了三个参数,PluginListener,
        //OverlayPlugin.class,和一个boolean值true
        Dependency.get(PluginManager.class).addPluginListener(
                new PluginListener<OverlayPlugin>() {
                    private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();

                    @Override
                    public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
                        
                        mainHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                StatusBar statusBar = getComponent(StatusBar.class);
                                if (statusBar != null) {
                                    plugin.setup(statusBar.getStatusBarWindow(),
                                            statusBar.getNavigationBarView(), new Callback(plugin));
                                }
                            }
                        });
                    }

                    @Override
                    public void onPluginDisconnected(OverlayPlugin plugin) {
                        mainHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mOverlays.remove(plugin);
                                Dependency.get(StatusBarWindowController.class).setForcePluginOpen(
                                        mOverlays.size() != 0);
                            }
                        });
                    }

                    class Callback implements OverlayPlugin.Callback {
                        private final OverlayPlugin mPlugin;

                        Callback(OverlayPlugin plugin) {
                            mPlugin = plugin;
                        }

                        @Override
                        public void onHoldStatusBarOpenChange() {
                            if (mPlugin.holdStatusBarOpen()) {
                                mOverlays.add(mPlugin);
                            } else {
                                mOverlays.remove(mPlugin);
                            }
                            mainHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    Dependency.get(StatusBarWindowController.class)
                                            .setStateListener(b -> mOverlays.forEach(
                                                    o -> o.setCollapseDesired(b)));
                                    Dependency.get(StatusBarWindowController.class)
                                            .setForcePluginOpen(mOverlays.size() != 0);
                                }
                            });
                        }
                    }
                }, OverlayPlugin.class, true /* Allow multiple plugins */);

        mServicesStarted = true;
    }

Dependency是定义在config_systemUIServiceComponents这个config文件中的,在startServicesIfNeeded中会遍历此config定义的所有SystemUI重要类,调用它们的Start方法:

Dependency.start

@Override
    public void start() {
        // TODO: Think about ways to push these creation rules out of Dependency to cut down
        // on imports.
        mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get);
        mProviders.put(BG_LOOPER, mBgLooper::get);
        mProviders.put(BG_HANDLER, mBgHandler::get);
        mProviders.put(MAIN_HANDLER, mMainHandler::get);
        mProviders.put(ActivityStarter.class, mActivityStarter::get);
        mProviders.put(ActivityStarterDelegate.class, mActivityStarterDelegate::get);

        mProviders.put(AsyncSensorManager.class, mAsyncSensorManager::get);

        mProviders.put(BluetoothController.class, mBluetoothController::get);
        mProviders.put(SensorPrivacyManager.class, mSensorPrivacyManager::get);

        mProviders.put(LocationController.class, mLocationController::get);

        mProviders.put(RotationLockController.class, mRotationLockController::get);

        mProviders.put(NetworkController.class, mNetworkController::get);

        mProviders.put(ZenModeController.class, mZenModeController::get);

        mProviders.put(HotspotController.class, mHotspotController::get);

        mProviders.put(CastController.class, mCastController::get);

        mProviders.put(FlashlightController.class, mFlashlightController::get);

        mProviders.put(KeyguardMonitor.class, mKeyguardMonitor::get);

        mProviders.put(UserSwitcherController.class, mUserSwitcherController::get);

        mProviders.put(UserInfoController.class, mUserInfoController::get);

        mProviders.put(BatteryController.class, mBatteryController::get);

        
        	......
        
        sDependency = this;
    }

我们可以看到,start方法中将很多的类添加到了mProviders中,接着看:

Dependency.get

private static Dependency sDependency;
@Deprecated
    public static <T> T get(Class<T> cls) {
        return sDependency.getDependency(cls);
    }
    protected final <T> T getDependency(Class<T> cls) {
        return getDependencyInner(cls);
    }
    private synchronized <T> T getDependencyInner(Object key) {
        @SuppressWarnings("unchecked")
        T obj = (T) mDependencies.get(key);
        if (obj == null) {
            obj = createDependency(key);
            mDependencies.put(key, obj);
        }
        return obj;
    }

get方法最终通过mDependencies.get来获取对象,mDependencies是个ArrayMap,如果没有获取到就调用createDependency创建对象,创建之后放入mDependencies中

createDependency

@VisibleForTesting
    protected <T> T createDependency(Object cls) {
        
        @SuppressWarnings("unchecked")
        LazyDependencyCreator<T> provider = mProviders.get(cls);
        if (provider == null) {
            throw new IllegalArgumentException("Unsupported dependency " + cls
                    + ". " + mProviders.size() + " providers known.");
        }
        return provider.createDependency();
    }

此方法通过mProviders.get来获取对象,mProviders中的类就是在Start方法中添加的,所以能够直接获取,Dependency中用到了dagger框架的Lazy,Provider等机制。

addPluginListener

所以我们在看到Dependency.get(T.class)时就可以简单认为是获取T的实现类
接着SystemUIApplication的startServicesIfNeeded方法添加插件监听,这里实际调用PluginManagerImpl的addPluginListener方法,此方法接收三个参数:一个PluginListener接口,一个Class对象,一个boolean值

PluginManagerImpl中的addPluginListener有几个重载,为了好说明,我给它们编了个号

1public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls) {
        addPluginListener(listener, cls, false);
    }
	(2public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
            boolean allowMultiple) {
        addPluginListener(PluginManager.Helper.getAction(cls), listener, cls, allowMultiple);
    }
	(3public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
            Class<?> cls) {
        addPluginListener(action, listener, cls, false);
    }
	(4public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
            Class cls, boolean allowMultiple) {
        android.util.Log.d("djtang","addPluginListener...action = :"+action+",name = :"+cls.getName());
        mPluginPrefs.addAction(action);
        PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
                allowMultiple, mLooper, cls, this);
        p.loadAll();
        mPluginMap.put(listener, p);
        startListening();
    }

PluginListener

我们先来看下PluginListener这个接口,这是个泛型接口,其中T必须是Plugin的子类,此接口提供两个生命周期方法,插件连接时调用onPluginConnected,断开连接调用
onPluginDisconnected

public interface PluginListener<T extends Plugin> {
   
    void onPluginConnected(T plugin, Context pluginContext);

    
    default void onPluginDisconnected(T plugin) {

    }
}

从上面代码我们知道,Dependency.get(PluginManager.class).addPluginListener调用的是(2)号重载方法,获取了一个Action后调用了(4)号方法,看下Action是啥:

PluginManager.Helper.getAction(cls)

public interface PluginManager {
	class Helper {
        public static <P> String getAction(Class<P> cls) {
        	//获取ProvidesInterface的注解信息
            ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
            if (info == null) {
                throw new RuntimeException(cls + " doesn't provide an interface");
            }
            if (TextUtils.isEmpty(info.action())) {
                throw new RuntimeException(cls + " doesn't provide an action");
            }
            //获取ProvidesInterface注解的action
            return info.action();
        }
}

通过getDeclaredAnnotation方法获取注解,ProvidesInterface这是个注解类,每个继承Plugin的类包含一个ProvidesInterface,这个注解类包含两项,version和action

public @interface ProvidesInterface {
    int version();

    String action() default "";

}

用法如下:

@ProvidesInterface(action = MyPlugin.ACTION, version = MyPlugin.VERSION)
public interface MyPlugin extends Plugin {
    String ACTION = "com.android.systemui.action.PLUGIN_MY_PLUGIN";
    int VERSION = 1;
    ...
}

这样就通过ProvidesInterface注解将action和version暴露了出来,获取的方式很简单,调用ProvidesInterface的action方法获取的就是其action

public interface PluginManager {
	class Helper {
        public static <P> String getAction(Class<P> cls) {
            ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
            if (info == null) {
                throw new RuntimeException(cls + " doesn't provide an interface");
            }
            if (TextUtils.isEmpty(info.action())) {
                throw new RuntimeException(cls + " doesn't provide an action");
            }
            return info.action();
        }
 }

我们再回到Dependency.get(PluginManager.class).addPluginListener的方法,它的第二个参数是OverlayPlugin.class

OverlayPlugin


@ProvidesInterface(action = OverlayPlugin.ACTION, version = OverlayPlugin.VERSION)
public interface OverlayPlugin extends Plugin {
    String ACTION = "com.android.systemui.action.PLUGIN_OVERLAY";
    int VERSION = 3;
    	.....
    }

根据我们上面的分析,就知道了在(2)号方法中获取的action就是OverlayPlugin中定义的ACTION = “com.android.systemui.action.PLUGIN_OVERLAY”,通过ProvidesInterface注解获取,好了接着(2)号方法调到了(4)号方法:

public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
            Class cls, boolean allowMultiple) {
        mPluginPrefs.addAction(action);
        PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
                allowMultiple, mLooper, cls, this);
        p.loadAll();
        mPluginMap.put(listener, p);
        startListening();
    }

首先将action添加到mPluginPrefs,mPluginPrefs是一个PluginPrefs,它的内部有一个ArraySet和一个SharedPreferences,它的存储机制就是将action先存储到ArraySet,再将此ArraySet存到SharedPreferences中,具体代码就不贴出了

接着mFactory.createPluginInstanceManager方法,mFactory是PluginInstanceManagerFactory类型,是PluginManagerImpl的静态内部类

@VisibleForTesting
    public static class PluginInstanceManagerFactory {
        public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
                String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,
                Class<?> cls, PluginManagerImpl manager) {
            return new PluginInstanceManager(context, action, listener, allowMultiple, looper,
                    new VersionInfo().addClass(cls), manager);
        }
    }

createPluginInstanceManager其实就是new了一个PluginInstanceManager对象,
接着调用了PluginInstanceManager的loadAll方法

PluginInstanceManager.loadAll()

public void loadAll() {
        if (DEBUG) Log.d(TAG, "startListening");
        mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
    }

通过handler处理消息,注意mPluginHandler这个handler,它发送的消息并不是到主线程的,因为它使用的不是主线程的Looper,这个looper其实是:
mProviders.put(BG_LOOPER, mBgLooper::get),是一个后台Looper

PluginInstanceManager(Context context, PackageManager pm, String action,
            PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
            PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
        mMainHandler = new MainHandler(Looper.getMainLooper());
        mPluginHandler = new PluginHandler(looper);
        ...
    }

QUERY_ALL

接着看mPluginHandler里的具体处理:

private class PluginHandler extends Handler {
		private final ArrayList<PluginInfo<T>> mPlugins = new ArrayList<>();
		public void handleMessage(Message msg) {
            switch (msg.what) {
                case QUERY_ALL:
                    if (DEBUG) Log.d(TAG, "queryAll " + mAction);
                    //如果mPlugins不为空,则遍历mPlugins,调用onPluginDisconnected
                    //清理Plugin
                    for (int i = mPlugins.size() - 1; i >= 0; i--) {
                        PluginInfo<T> plugin = mPlugins.get(i);
                        mListener.onPluginDisconnected(plugin.mPlugin);
                        if (!(plugin.mPlugin instanceof PluginFragment)) {

                            plugin.mPlugin.onDestroy();
                        }
                    }
                    //清空mPlugins
                    mPlugins.clear();
                    handleQueryPlugins(null);
                    break;
                    .....
             }
}

handleQueryPlugins

private void handleQueryPlugins(String pkgName) {
            
             Intent intent = new Intent(mAction);
             //pkgName == null,此处的intent只有action,没有pkgName
            if (pkgName != null) {
                intent.setPackage(pkgName);
            }
            //給定intent,返回满足条件的ResolveInfo(本质是service)集合
            List<ResolveInfo> result = mPm.queryIntentServices(intent, 0);
            if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");
            //mAllowMultiple == true,不会走进去
            if (result.size() > 1 && !mAllowMultiple) {
                Log.w(TAG, "Multiple plugins found for " + mAction);
                if (DEBUG) {
                    for (ResolveInfo info : result) {
                        ComponentName name = new ComponentName(info.serviceInfo.packageName,
                                info.serviceInfo.name);
                        Log.w(TAG, "  " + name);
                    }
                }
                return;
            }
            //遍历ResolveInfo
            for (ResolveInfo info : result) {
                ComponentName name = new ComponentName(info.serviceInfo.packageName,
                        info.serviceInfo.name);
                 //根据info信息创建插件
                PluginInfo<T> t = handleLoadPlugin(name);
                if (t == null) continue;

                //如果成功创建了PluginInfo就添加到mPlugins保存
                mPlugins.add(t);
                //将创建好的PluginInfo发送到主线程处理
                mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();
            }
        }

PLUGIN_CONNECTED

private class MainHandler extends Handler {
	public void handleMessage(Message msg) {
            switch (msg.what) {
                case PLUGIN_CONNECTED:
                    if (DEBUG) Log.d(TAG, "onPluginConnected");
                    PluginPrefs.setHasPlugins(mContext);
                    //将handler发送过来的obj强转为PluginInfo
                    PluginInfo<T> info = (PluginInfo<T>) msg.obj;
                    mManager.handleWtfs();
                    //如果是Fragment类型的Plugin
                    if (!(msg.obj instanceof PluginFragment)) {
                      	//调用它的onCreate方法
                        info.mPlugin.onCreate(mContext, info.mPluginContext);
                    }
                    //调用onPluginConnected方法
                    mListener.onPluginConnected(info.mPlugin, info.mPluginContext);
                    break;
                    ......
	}
}

我们可以看到mPluginHandler和mMainHandler的逻辑还是比较对称的:

  1. mPluginHandler在后台线程处理消息,在收到QUERY_ALL消息后如果有Plugin则先判断是否是Fragment类型Plugin,如果是则调用onDestroy方法,还会调用Plugin添加的PluginListener的回调onPluginDisconnected
  2. mMainHandler在主线程处理mPluginHandler发送来的Plugin,同样判断如果是Fragment类型Plugin则调用onCreate,还会调用Plugin添加的PluginListener的回调onPluginConnected

我们再会到addPluginListener,经过上面的分析,我们知道了PluginInstanceManager是一个专门用来管理Plugin的类,每个Plugin对应一个

public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
            Class cls, boolean allowMultiple) {
        mPluginPrefs.addAction(action);
        PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
                allowMultiple, mLooper, cls, this);
        p.loadAll();
        mPluginMap.put(listener, p);
        startListening();
    }

mPluginMap是一个ArrayMap,将同一个Plugin的listener和PluginInstanceManager一一对应的保存进去

private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
            = new ArrayMap<>();

startListening()

private void startListening() {
		//保证只启动一次
        if (mListening) return;
        mListening = true;
        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(PLUGIN_CHANGED);
        filter.addAction(DISABLE_PLUGIN);
        filter.addDataScheme("package");
        mContext.registerReceiver(this, filter);
        filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
        mContext.registerReceiver(this, filter);
    }

这个方法就是注册了一些广播,PluginManagerImpl继承BroadcastReceiver,所有收到广播的处理都在它自己的onReceive方法中:

public void onReceive(Context context, Intent intent) {
	if(Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())){
		......
	}else if(DISABLE_PLUGIN.equals(intent.getAction())){
		......
	}else {
           .....
           if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                for (PluginInstanceManager manager : mPluginMap.values()) {
                    manager.onPackageChange(pkg);
                }
            } else {
                for (PluginInstanceManager manager : mPluginMap.values()) {
                    manager.onPackageRemoved(pkg);
                }
            }
	}
}

我们可以看到,else分支中如果是ACTION_PACKAGE_REMOVED广播则调用
manager.onPackageRemoved,否则调用manager.onPackageChange,这两个方法在PluginInstanceManager类中,其实它们是一对相对应的方法,一个onPackageRemoved最终会调到PluginListener的onPluginDisconnected中,
onPackageChange最终会调到PluginListener的onPluginConnected中,我们看下具体代码:

PluginInstanceManager

onPackageChange中相当于先调了一次onPackageRemoved

public void onPackageRemoved(String pkg) {
        mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
    }
    
public void onPackageChange(String pkg) {
        mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
        mPluginHandler.obtainMessage(PluginHandler.QUERY_PKG, pkg).sendToTarget();
    }

QUERY_PKG和REMOVE_PKG

private class PluginHandler extends Handler {
	public void handleMessage(Message msg) {
		switch (msg.what) {
			case REMOVE_PKG:
                    mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,
                                    plugin.mPlugin).sendToTarget();

                    break;
			case QUERY_PKG:
                    String p = (String) msg.obj;
                    handleQueryPlugins(p);
                    .....
                    break;
              } 
	}
}

REMOVE_PKG中向MainHandler主线程发送了PLUGIN_DISCONNECTED的msg,QUERY_PKG中调用了handleQueryPlugins方法,此方法前面已经分析过了,最终是向MainHandler主线程发送了PLUGIN_CONNECTED的msg

private class MainHandler extends Handler {
		switch (msg.what) {
			case PLUGIN_CONNECTED:
	                ......
                    mListener.onPluginConnected(info.mPlugin, info.mPluginContext);
                    break;
                case PLUGIN_DISCONNECTED:
                    mListener.onPluginDisconnected((T) msg.obj);
                  	......
                    break;
			}
}

我们看到startListening注册的广播里处理了PluginListener的回调

本篇以SystemUI启动过程中添加的OverlayPlugin为例分析了SystemUI的插件化机制Plugin

关于Plugin作一个总结:
Systemui插件化机制的添加步骤:

  1. 创建一个继承自Plugin或者FragmentBase的接口,定义ACTION和VERSION,使用ProvidesInterface注解将ACTION和VERSION暴露出去
  2. 创建PluginListener接口作为Plugin的回调
  3. 调用PluginManagerImpl的addPluginListener方法添加PluginListener和Plugin

SystemUI插件化的目的就是使开发者能够轻松随意替换SystemUI的一些组件,而不需要修改大量代码,在AOSP提供的官方doc中提到要使用插件化Plugin的条件有:

  1. 必须使用平台证书进行签名
  2. 必须在LOCAL_JAVA_LIBRARIES中包含SystemUIPluginLib(不能是LOCAL_STATIC_JAVA_LIBRARIES)
  3. 声明插件还需要在清单文件中注册类似如下代码:
       <service android:name=".SampleOverlayPlugin"
            android:label="@string/plugin_label">
            <intent-filter>
                <action android:name="com.android.systemui.action.PLUGIN_OVERLAY" />
            intent-filter>
        service>
  1. 需要添加相应权限:
<uses-permission android:name="com.android.systemui.permission.PLUGIN" />
  1. 然后实现你需要替换的SystemUI组件的提供的插件接口
@Requires(target = OverlayPlugin.class, version = OverlayPlugin.VERSION)
public class SampleOverlayPlugin implements OverlayPlugin {
    ...
}

你可能感兴趣的:(笔记)