0.前情提要
SystemUIApplication.java
1.SystemUIApplication的startServicesIfNeeded函數(shù)
public void startServicesIfNeeded() {
String[] names =getResources().getStringArray(R.array.config_systemUIServiceComponents);
startServicesIfNeeded(names);
}
2.在startServicesIfNeeded中先是啟動(dòng)了一堆組件,然后添加了Plugin的監(jiān)聽
private void startServicesIfNeeded(String[] services) {
//啟動(dòng)了一堆組件
//獲取PluginManagerImpl對(duì)象略贮,并添加插件監(jiān)聽
Dependency.get(PluginManager.class).addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays;
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
//onPluginConnected連接成功以后溶其,拿到對(duì)象
StatusBar statusBar = getComponent(StatusBar.class);
if (statusBar != null) {
//調(diào)用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對(duì)應(yīng)的類就是PluginManagerIml.java置济,可以看到它調(diào)用的是重載方法2,最終會(huì)調(diào)用的是重載方法4啃洋,其實(shí)對(duì)應(yīng)的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();
}
}
核心流程
簡化一下也就是相當(dāng)于執(zhí)行以下這段程序坞古,關(guān)鍵的步驟也就是以下的流程
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的關(guān)于ProvidesInterface注解里的action值
//action值是 OverlayPlugin.ACTION="com.android.systemui.action.PLUGIN_OVERLAY"
String action=PluginManager.getAction(OverlayPlugin.class);
//將拿到的action值添加到SharedPreferences中
mPluginPrefs.addAction(action);
//第一步,通過PluginInstanceManagerFactory工廠創(chuàng)建一個(gè)PluginInstanceManager的實(shí)例
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action,
listener,true, mLooper, OverlayPlugin.class, this);
//第二步辞居,加載Plugin實(shí)例
p.loadAll();
//把Plugin實(shí)例添加到map映射中
mPluginMap.put(listener, p);
//第三步楷怒,監(jiān)聽Plugin實(shí)例
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.第一步,創(chuàng)建PluginInstanceManager 對(duì)象
PluginInstanceManagerFactory.java
接下來我們要看下PluginInstanceManagerFactory里面是創(chuàng)建的PluginInstanceManager對(duì)象的方式也比較簡單瓦灶,直接就是new一個(gè)對(duì)象鸠删,其實(shí)的參數(shù)值我們列一下
context:Application對(duì)象(來自于SystemUIApplication)
action:"com.android.systemui.action.PLUGIN_OVERLAY"
listener:PluginListener對(duì)象(SystemUIApplication中的new PluginListener對(duì)象)
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在此就已經(jīng)注冊(cè)進(jìn)來了
mAllowMultiple = allowMultiple;
mVersion = version;
isDebuggable = debuggable;
}
}
綜上所述,SystemUI一起來的時(shí)候倚搬,就通過PluginManagerIml將其listener注冊(cè)到了PluginInstanceManager中,
2.第二步乾蛤,通過loadAll生成PluginInfo對(duì)象
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對(duì)象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) {
//這實(shí)際上不是一項(xiàng)服務(wù),也不應(yīng)該啟動(dòng)家卖,但它是一種方便的基于PM的插件管理方式眨层。
Intent intent = new Intent(mAction);
if (pkgName != null) {
intent.setPackage(pkgName);
}
//通過"com.android.systemui.action.PLUGIN_OVERLAY"查詢到對(duì)應(yīng)的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對(duì)應(yīng)的ComponentName
ComponentName name = new ComponentName(info.serviceInfo.packageName,
info.serviceInfo.name);
//生成PluginInfo對(duì)象
PluginInfo<T> t = handleLoadPlugin(name);
if (t == null) continue;
//通知listener,pluginInfo對(duì)象已經(jīng)成功連接了
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;
}
//創(chuàng)建PluginManagerImpl的ClassLoader上荡,這樣我們就可以使用我們自己的代碼作為父代碼趴樱。
ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
//構(gòu)建PluginContextWrapper
Context pluginContext = new PluginContextWrapper(
mContext.createApplicationContext(info, 0), classLoader);
//通過反射生成對(duì)應(yīng)的plugin對(duì)象
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");
//最終創(chuàng)建PluginInfo對(duì)象
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.第三步,回調(diào)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);
}
//回調(diào)onPluginConnected結(jié)果
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里面的函數(shù)酪捡,我們知道onPluginConnected成功以后叁征,會(huì)先拿到StatusBar對(duì)象,并通過plugin的setup函數(shù)將StatusBar對(duì)象傳遞出去逛薇。
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);
}
}
}
}