本文基于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重新加载插件资源
以上操作便是添加一个插件监听器的工作流程
加载插件资源
扫描插件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);
}创建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);
}创建PluginContext
检查版本号,版本检查的是Plugin接口和其实现类两个的版本号,不匹配直接抛出异常,插件异常被捕获后PluginActionManager会禁用这个插件
调用插件类的生命周期函数Plugin::onCreate
回调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
调用
PluginListener::onPluginDisconnected,此时应当重置UI等状态触发
Plugin::onDestroy函数回调