0.前情提要
SystemUIApplication.java
1.SystemUIApplication的startServicesIfNeeded函数
public void startServicesIfNeeded() {
String[] names =getResources().getStringArray(R.array.config_systemUIServiceComponents);
startServicesIfNeeded(names);
}
2.在startServicesIfNeeded中先是启动了一堆组件,然后添加了Plugin的监听
private void startServicesIfNeeded(String[] services) {
//启动了一堆组件
//获取PluginManagerImpl对象,并添加插件监听
Dependency.get(PluginManager.class).addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays;
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
//onPluginConnected连接成功以后,拿到对象
StatusBar statusBar = getComponent(StatusBar.class);
if (statusBar != null) {
//调用plugin的setup事件
plugin.setup(statusBar.getStatusBarWindow(),
statusBar.getNavigationBarView());
}
// Lazy init.
if (mOverlays == null) mOverlays = new ArraySet<>();
if (plugin.holdStatusBarOpen()) {
mOverlays.add(plugin);
Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
mOverlays.forEach(o -> o.setCollapseDesired(b)));
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
}
@Override
public void onPluginDisconnected(OverlayPlugin plugin) {
mOverlays.remove(plugin);
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
}, OverlayPlugin.class, true /* Allow multiple plugins */);
mServicesStarted = true;
}
PluginManagerIml.java
3.这里通过Dependency拿PluginManager.class对应的类就是PluginManagerIml.java,可以看到它调用的是重载方法2,最终会调用的是重载方法4,其实对应的action=PluginManager.getAction(PluginManager.class),
public class PluginManagerImpl extends BroadcastReceiver implements PluginManager {
public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
boolean allowMultiple) {
addPluginListener(PluginManager.getAction(cls), listener, cls, allowMultiple);
}
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
Class cls, boolean allowMultiple) {
if (!isDebuggable) {
// Never ever ever allow these on production builds, they are only for prototyping.
return;
}
mPluginPrefs.addAction(action);
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
allowMultiple, mLooper, cls, this);
p.loadAll();
mPluginMap.put(listener, p);
startListening();
}
}
核心流程
简化一下也就是相当于执行以下这段程序,关键的步骤也就是以下的流程
public <T extends Plugin> void addPluginListener(PluginListener<T> listener) {
if (!isDebuggable) {
// Never ever ever allow these on production builds, they are only for prototyping.
return;
}
//getAction,拿到的OverlayPlugin的关于ProvidesInterface注解里的action值
//action值是 OverlayPlugin.ACTION="com.android.systemui.action.PLUGIN_OVERLAY"
String action=PluginManager.getAction(OverlayPlugin.class);
//将拿到的action值添加到SharedPreferences中
mPluginPrefs.addAction(action);
//第一步,通过PluginInstanceManagerFactory工厂创建一个PluginInstanceManager的实例
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action,
listener,true, mLooper, OverlayPlugin.class, this);
//第二步,加载Plugin实例
p.loadAll();
//把Plugin实例添加到map映射中
mPluginMap.put(listener, p);
//第三步,监听Plugin实例
startListening();
}
PluginManager.java
public interface PluginManager {
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();
}
}
OverlayPlugin.java
@ProvidesInterface(action = OverlayPlugin.ACTION, version = OverlayPlugin.VERSION)
public interface OverlayPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_OVERLAY";
int VERSION = 2;
void setup(View statusBar, View navBar);
default boolean holdStatusBarOpen() {
return false;
}
/**
* Only called if the plugin has returned true to holdStatusBarOpen().
*/
default void setCollapseDesired(boolean collapseDesired) {
}
}
注解 ProvidesInterface.java
@Retention(RetentionPolicy.RUNTIME)
public @interface ProvidesInterface {
int version();
String action() default "";
}
1.第一步,创建PluginInstanceManager 对象
PluginInstanceManagerFactory.java
接下来我们要看下PluginInstanceManagerFactory里面是创建的PluginInstanceManager对象的方式也比较简单,直接就是new一个对象,其实的参数值我们列一下
context:Application对象(来自于SystemUIApplication)
action:"com.android.systemui.action.PLUGIN_OVERLAY"
listener:PluginListener对象(SystemUIApplication中的new PluginListener对象)
allowMultiple:true
looper:new HandlerThread("SysUiBg",Process.THREAD_PRIORITY_BACKGROUND).getLooper();
(来自于SystemUIApplication)
versionInfo:OverlayPlugin.cls,用于保存OverlayPlugin的版本信息
manager:PluginManagerImpl .this
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);
}
}
PluginInstanceManager.java
public class PluginInstanceManager<T extends Plugin> {
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
this(context, context.getPackageManager(), action, listener, allowMultiple, looper,
version,manager, Build.IS_DEBUGGABLE);
}
@VisibleForTesting
PluginInstanceManager(Context context, PackageManager pm, String action,
PluginListener<T> listener, boolean allowMultiple, Looper looper,
VersionInfo version,PluginManagerImpl manager, boolean debuggable) {
mMainHandler = new MainHandler(Looper.getMainLooper());
mPluginHandler = new PluginHandler(looper);
mManager = manager;
mContext = context;
mPm = pm;
mAction = action;
mListener = listener;//listener在此就已经注册进来了
mAllowMultiple = allowMultiple;
mVersion = version;
isDebuggable = debuggable;
}
}
综上所述,SystemUI一起来的时候,就通过PluginManagerIml将其listener注册到了PluginInstanceManager中,
2.第二步,通过loadAll生成PluginInfo对象
private class PluginHandler extends Handler {
private final ArrayList<PluginInfo<T>> mPlugins = new ArrayList<>();
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case QUERY_ALL:
//先将plugins中所有Pluginc对象onDestroy,并clear掉plugins
for (int i = mPlugins.size() - 1; i >= 0; i--) {
PluginInfo<T> plugin = mPlugins.get(i);
mListener.onPluginDisconnected(plugin.mPlugin);
if (!(plugin.mPlugin instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onDestroy as part of the fragment lifecycle.
plugin.mPlugin.onDestroy();
}
}
mPlugins.clear();
handleQueryPlugins(null);
break;
}
}
private void handleQueryPlugins(String pkgName) {
//这实际上不是一项服务,也不应该启动,但它是一种方便的基于PM的插件管理方式。
Intent intent = new Intent(mAction);
if (pkgName != null) {
intent.setPackage(pkgName);
}
//通过"com.android.systemui.action.PLUGIN_OVERLAY"查询到对应的ResolveInfo列表
List<ResolveInfo> result =
mPm.queryIntentServices(intent, 0);
if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");
if (result.size() > 1 && !mAllowMultiple) {
//如果列表大于1的话,不处理
Log.w(TAG, "Multiple plugins found for " + mAction);
return;
}
for (ResolveInfo info : result) {
//拿到PLUGIN_OVERLAY对应的ComponentName
ComponentName name = new ComponentName(info.serviceInfo.packageName,
info.serviceInfo.name);
//生成PluginInfo对象
PluginInfo<T> t = handleLoadPlugin(name);
if (t == null) continue;
//通知listener,pluginInfo对象已经成功连接了
mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();
mPlugins.add(t);
}
}
protected PluginInfo<T> handleLoadPlugin(ComponentName component) {
// This was already checked, but do it again here to make extra extra sure, we don't
// use these on production builds.
if (!isDebuggable) {
// Never ever ever allow these on production builds, they are only for prototyping.
Log.d(TAG, "Somehow hit second debuggable check");
return null;
}
//获取包名和类名
String pkg = component.getPackageName();
String cls = component.getClassName();
try {
ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
// TODO: This probably isn't needed given that we don't have IGNORE_SECURITY on
if (mPm.checkPermission(PLUGIN_PERMISSION, pkg)
!= PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Plugin doesn't have permission: " + pkg);
return null;
}
//创建PluginManagerImpl的ClassLoader,这样我们就可以使用我们自己的代码作为父代码。
ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
//构建PluginContextWrapper
Context pluginContext = new PluginContextWrapper(
mContext.createApplicationContext(info, 0), classLoader);
//通过反射生成对应的plugin对象
Class<?> pluginClass = Class.forName(cls, true, classLoader);
// TODO: Only create the plugin before version check if we need it for
// legacy version check.
T plugin = (T) pluginClass.newInstance();
try {
VersionInfo version = checkVersion(pluginClass, plugin, mVersion);
if (DEBUG) Log.d(TAG, "createPlugin");
//最终创建PluginInfo对象
return new PluginInfo(pkg, cls, plugin, pluginContext, version);
} catch (InvalidVersionException e) {
final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
mContext.getPackageName());
final int color = Resources.getSystem().getIdentifier(
"system_notification_accent_color", "color", "android");
final Notification.Builder nb = new Notification.Builder(mContext,
PluginManager.NOTIFICATION_CHANNEL_ID)
.setStyle(new Notification.BigTextStyle())
.setSmallIcon(icon)
.setWhen(0)
.setShowWhen(false)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(mContext.getColor(color));
String label = cls;
try {
label = mPm.getServiceInfo(component, 0).loadLabel(mPm).toString();
} catch (NameNotFoundException e2) {
}
if (!e.isTooNew()) {
// Localization not required as this will never ever appear in a user build.
nb.setContentTitle("Plugin \"" + label + "\" is too old")
.setContentText("Contact plugin developer to get an updated"
+ " version.\n" + e.getMessage());
} else {
// Localization not required as this will never ever appear in a user build.
nb.setContentTitle("Plugin \"" + label + "\" is too new")
.setContentText("Check to see if an OTA is available.\n"
+ e.getMessage());
}
Intent i = new Intent(PluginManagerImpl.DISABLE_PLUGIN).setData(
Uri.parse("package://" + component.flattenToString()));
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
mContext.getSystemService(NotificationManager.class)
.notifyAsUser(cls, SystemMessage.NOTE_PLUGIN, nb.build(),
UserHandle.ALL);
// TODO: Warn user.
Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
+ ", expected " + mVersion);
return null;
}
} catch (Throwable e) {
Log.w(TAG, "Couldn't load plugin: " + pkg, e);
return null;
}
}
}
3.第三步,回调onPluginConnected
private class MainHandler extends Handler {
private static final int PLUGIN_CONNECTED = 1;
private static final int PLUGIN_DISCONNECTED = 2;
public MainHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PLUGIN_CONNECTED:
if (DEBUG) Log.d(TAG, "onPluginConnected");
PluginPrefs.setHasPlugins(mContext);
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
mManager.handleWtfs();
if (!(msg.obj instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onCreate as part of the fragment lifecycle.
info.mPlugin.onCreate(mContext, info.mPluginContext);
}
//回调onPluginConnected结果
mListener.onPluginConnected(info.mPlugin, info.mPluginContext);
break;
case PLUGIN_DISCONNECTED:
if (DEBUG) Log.d(TAG, "onPluginDisconnected");
mListener.onPluginDisconnected((T) msg.obj);
if (!(msg.obj instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onDestroy as part of the fragment lifecycle.
((T) msg.obj).onDestroy();
}
break;
default:
super.handleMessage(msg);
break;
}
}
}
通过SystemUIApplication.java里面的函数,我们知道onPluginConnected成功以后,会先拿到StatusBar对象,并通过plugin的setup函数将StatusBar对象传递出去。
4.第四步,startListener(PluginManagerImpl.java)
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_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);
}
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
for (PluginInstanceManager manager : mPluginMap.values()) {
manager.loadAll();
}
} else if (DISABLE_PLUGIN.equals(intent.getAction())) {
//组件不可用
Uri uri = intent.getData();
ComponentName component = ComponentName.unflattenFromString(
uri.toString().substring(10));
mContext.getPackageManager().setComponentEnabledSetting(component,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(),
SystemMessage.NOTE_PLUGIN);
} else {
Uri data = intent.getData();
String pkg = data.getEncodedSchemeSpecificPart();
if (mOneShotPackages.contains(pkg)) {
int icon = mContext.getResources().getIdentifier("tuner", "drawable",
mContext.getPackageName());
int color = Resources.getSystem().getIdentifier(
"system_notification_accent_color", "color", "android");
String label = pkg;
try {
PackageManager pm = mContext.getPackageManager();
label = pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString();
} catch (NameNotFoundException e) {
}
// Localization not required as this will never ever appear in a user build.
final Notification.Builder nb =
new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(icon)
.setWhen(0)
.setShowWhen(false)
.setPriority(Notification.PRIORITY_MAX)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(mContext.getColor(color))
.setContentTitle("Plugin \"" + label + "\" has updated")
.setContentText("Restart SysUI for changes to take effect.");
Intent i = new Intent("com.android.systemui.action.RESTART").setData(
Uri.parse("package://" + pkg));
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
nb.addAction(new Action.Builder(null, "Restart SysUI", pi).build());
mContext.getSystemService(NotificationManager.class).notifyAsUser(pkg,
SystemMessage.NOTE_PLUGIN, nb.build(), UserHandle.ALL);
}
if (clearClassLoader(pkg)) {
Toast.makeText(mContext, "Reloading " + pkg, Toast.LENGTH_LONG).show();
}
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);
}
}
}
}