本文基于Android-15.0.0_r22 aosp

PluginManager初始化

注册插件监听器

PluginManager所有功能均有PluginManagerImpl类实现。

SystemUI每一个插件化的功能或者服务在初始化时会创建一个PluginListener对象并调用接口PluginManager::addPluginListener

addPluginListener函数会创建其对应的PluginActionManager,然后将其保存到mPluginMap中,key是PluginListener,value是PluginActionManager

ActionManager封装了插件的ACTION,PluginClass,PluginListener

监听插件变化

然后PluginManager::startListening尝试开启广播监听,如果已经开启就会跳过,如果是进程启动后的第一次发起监听,startListening将监听ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED,ACTION_PACKAGE_REPLACED,ACTION_PACKAGE_REMOVED,PLUGIN_CHANGED,DISABLE_PLUGIN这几个广播

PluginManager::onReceive收到插件安装或者变化广播时遍历mPluginMap的所有value调用PluginActionManager::reloadPackage重新加载插件资源

以上操作便是添加一个插件监听器的工作流程

graph TD A["创建 PluginListener 对象"] --> B["注册到 PluginManager"] B --> C["PluginManager 内部<br/>创建 PluginActionManager<br/>(关联 PluginListener、插件类、ACTION)"] C --> D["PluginManager 检查广播监听状态"] D --> E{"广播监听是否已启动?"} E -->|是| F["等待广播"] E -->|否| G["注册监听<br/>包变化和插件广播"] G --> F F --> H["收到广播,BroadcastReceiver 触发"] H --> I["PluginManager 遍历 mPluginMap"] I --> J["对每个 PluginActionManager<br/>调用重新加载插件资源"] J --> F

加载插件资源

扫描插件Component信息

当监听到插件变化时,遍历所有的PlauginActionManager刷新插件资源

刷新接口:PlauginActionManager::reloadPackage干了两件事:删除旧包(做个包名判断,包名相同才删除),加载新包。

广播中可以读取到插件的包名.

每一个插件都需要实现Plugin接口,这个接口定义在SystemUI侧,必须定义ACTION, ACTION的作用:当监听到插件变化通过pkg+action查询插件信息,代码如下:

com/android/systemui/shared/plugins/PluginActionManager.java

    private void handleQueryPlugins(String pkgName) {
        Intent intent = new Intent(mAction);
        if (pkgName != null) {
            intent.setPackage(pkgName);
        }
        List<ResolveInfo> result = mPm.queryIntentServices(intent, 0);
     ...
    }

查询到插件的component信息,例如:ComponentInfo{com.android.systemui.plugin.testoverlayplugin/com.android.systemui.plugin.testoverlayplugin.SampleOverlayPlugin}

根据这个ComponentName构造一个PluginInstance对象

    private void handleQueryPlugins(String pkgName) {
        ...
        for (ResolveInfo info : result) {
            ComponentName name = new ComponentName(info.serviceInfo.packageName,
                    info.serviceInfo.name);
            PluginInstance<T> pluginInstance = loadPluginComponent(name);
                ...
                mMainExecutor.execute(() -> onPluginConnected(pluginInstance));
        }
    }

创建插件实例对象

插件实例对象的创建由PluginInstance::onCreate负责

/** Alerts listener and plugin that the plugin has been created. */
public synchronized void onCreate() {
    ...
    if (mPlugin == null) {
        log("onCreate: auto-load");
        loadPlugin();
        return;
    }

由于第一次创建的时候mPlugin没有初始化,为null, 主要由PluginInstance::loadPlugin

/**
 * Loads and creates the plugin if it does not exist.
 */
public synchronized void loadPlugin() {

    // Both of these calls take about 1 - 1.5 seconds in test runs
    //1
    mPlugin = mPluginFactory.createPlugin(this);
    //2
    mPluginContext = mPluginFactory.createPluginContext();
    ...
    //3
    if (!checkVersion()) {
        log("loadPlugin: version check failed");
        return;
    }

    log("Loaded plugin; running callbacks");
    //4
    if (!(mPlugin instanceof PluginFragment)) {
        // Only call onCreate for plugins that aren't fragments, as fragments
        // will get the onCreate as part of the fragment lifecycle.
        mPlugin.onCreate(mAppContext, mPluginContext);
    }
    //5
    mListener.onPluginLoaded(mPlugin, mPluginContext, this);
}
  1. 创建Plugin对象

mPluginFactory是一个内部类,使用反射的方式创建了Plugin对象

public T createPlugin(ProtectedPluginListener listener) {
    try {
        ClassLoader loader = mClassLoaderFactory.get();
        Class<T> instanceClass = (Class<T>) Class.forName(
                mComponentName.getClassName(), true, loader);
        T result = (T) mInstanceFactory.create(instanceClass);
        return PluginProtector.protectIfAble(result, listener);
}
  1. 创建PluginContext

  2. 检查版本号,版本检查的是Plugin接口和其实现类两个的版本号,不匹配直接抛出异常,插件异常被捕获后PluginActionManager会禁用这个插件

  3. 调用插件类的生命周期函数Plugin::onCreate

  4. 回调PluginListener::onPluginConnected

插件对象交互

当插件链接成功之后,通常在PluginListener::onPluginConnected中发起对插件的调用

例子如下

//com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
    mMainExecutor.execute(
            //替换SystemUI的UI为插件提供的资源
            () -> plugin.setup(
                    mNotificationShadeWindowController.getWindowRootView(),
                    getNavigationBarView(),
                    new Callback(plugin), mDozeParameters));
}

//com/android/systemui/doze/DozeService.java
    @Override
    public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) {
        mDozePlugin = plugin;
        mDozePlugin.setDozeRequester(this);
    }

后续就可以通过Plugin接口预定义的接口实现交互

插件卸载

当收到插件卸载广播时调用PluginActionManager::onPackageRemoved,如果包名匹配,销毁PluginInstance实例,PluginInstance::onDestroy

  1. 调用PluginListener::onPluginDisconnected,此时应当重置UI等状态

  2. 触发Plugin::onDestroy函数回调

春风花气馥,秋月寒江湛