Analysis of RePlugin Process Management and Plugin Loading Mechanism
This article provides a detailed source‑code analysis of RePlugin's process management, covering process startup, attachBaseContext handling, IPC initialization, PMF setup, plugin installation, synchronization across processes, and the internal mechanisms for loading and updating plugins.
This article offers a comprehensive source‑code analysis of RePlugin's process management mechanism, focusing on how processes are started, how plugins are loaded, and how the framework synchronizes plugin information across all processes.
Process startup : When the system calls RePluginApplication.attachBaseContext , it invokes RePlugin.App.attachBaseContext , which in turn calls RePluginInternal.init to set up the application context, configuration, IPC, HostConfigHelper, PluginStatusController, and PMF.
public static void attachBaseContext(Application app, RePluginConfig config) {
if (sAttached) { // avoid duplicate initialization
LogDebug.d(TAG, "attachBaseContext: Already called");
return;
}
RePluginInternal.init(app); // set AppContext reference
sConfig = config;
sConfig.initDefaults(app);
IPC.init(app); // initialize IPC process communication
// ... other initialization steps ...
HostConfigHelper.init();
PluginStatusController.setAppContext(app);
PMF.init(app);
sAttached = true;
}IPC initialization sets the current process name, pid, package name, persistent process name, and flags indicating whether the process is a UI or persistent process.
public static void init(Context context) {
sCurrentProcess = SysUtils.getCurrentProcessName();
sCurrentPid = Process.myPid();
sPackageName = context.getApplicationInfo().packageName;
// Determine persistent process name based on HostConfigHelper settings
if (HostConfigHelper.PERSISTENT_ENABLE) {
String cppn = HostConfigHelper.PERSISTENT_NAME;
if (!TextUtils.isEmpty(cppn)) {
sPersistentProcessName = cppn.startsWith(":") ? sPackageName + cppn : cppn;
} else {
sPersistentProcessName = sPackageName;
}
}
sIsUIProcess = sCurrentProcess.equals(sPackageName);
sIsPersistentProcess = sCurrentProcess.equals(sPersistentProcessName);
}PMF initialization creates the PluginManager, registers the process, and loads the default plugin if the current process is a stub (loader) process.
public static final void init(Application application) {
setApplicationContext(application);
PluginManager.init(application);
sPluginMgr = new PmBase(application);
sPluginMgr.init();
PatchClassLoaderUtils.patch(application);
}Plugin installation is performed via MP.install(String path) , which validates the file and then calls MP.pluginDownloaded . The pluginDownloaded method distinguishes between p‑n plugins and APK plugins, updates the plugin info, and notifies other processes.
public static PluginInfo install(String path) {
// Validate file
// ...
// For p‑n plugins, ensure they are in the allowed install directory
// ...
return MP.pluginDownloaded(path);
}Synchronizing plugin information is handled by syncInstalledPluginInfo2All in the persistent process. It updates the internal plugin table and broadcasts a NEW_PLUGIN intent to all processes.
private void syncInstalledPluginInfo2All(PluginInfo pi) {
PluginInfo needToSyncPi = (pi.getParentInfo() != null) ? pi.getParentInfo() : pi;
mPluginMgr.newPluginFound(needToSyncPi, false);
Intent intent = new Intent(PmBase.ACTION_NEW_PLUGIN);
intent.putExtra(RePluginConstants.KEY_PERSIST_NEED_RESTART, mNeedRestart);
intent.putExtra("obj", (Parcelable) needToSyncPi);
IPC.sendLocalBroadcast2AllSync(mContext, intent);
}Each process receives the broadcast and updates its PluginTable via PmBase.newPluginFound , which refreshes the plugin list, clears plugin status, and sends a local broadcast to external listeners.
final void newPluginFound(PluginInfo info, boolean persistNeedRestart) {
PluginTable.updatePlugin(info);
insertNewPlugin(info);
PluginStatusController.setStatus(info.getName(), info.getVersion(), PluginStatusController.STATUS_OK);
// Notify external listeners
Intent intent = new Intent(RePluginConstants.ACTION_NEW_PLUGIN);
intent.putExtra(RePluginConstants.KEY_PLUGIN_INFO, (Parcelable) info);
intent.putExtra(RePluginConstants.KEY_PERSIST_NEED_RESTART, persistNeedRestart);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}Adding a new plugin involves PmBase.insertNewPlugin , which checks for blocking, version conflicts, and whether the plugin is already loaded. If acceptable, it creates a Plugin instance and stores it.
final void insertNewPlugin(PluginInfo info) {
if (RePlugin.getConfig().getCallbacks().isPluginBlocked(info)) {
LogDebug.d(PLUGIN_TAG, "insert new plugin: plugin is blocked, in=" + info);
return;
}
Plugin p = mPlugins.get(info.getName());
if (p != null && p.isInitialized()) {
LogDebug.d(PLUGIN_TAG, "insert new plugin: failed cause plugin has loaded, plugin=" + info);
return;
}
mNeedRestart = true;
Plugin plugin = Plugin.build(info);
plugin.attach(mContext, mClassLoader, mLocal);
putPluginObject(info, plugin);
}Storing the plugin object is performed by putPluginObject . In the persistent process it also updates the plugins_up SharedPreferences cache.
private void putPluginObject(PluginInfo info, Plugin plugin) {
if (HostConfigHelper.PERSISTENT_ENABLE && IPC.isPersistentProcess()) {
SharedPreferences sp = Pref.getSharedPreferences("plugins_up");
sp.edit().putInt(info.getName(), plugin.mInfo.getVersion()).apply();
}
mPlugins.put(info.getPackageName(), plugin);
if (!TextUtils.isEmpty(info.getAlias())) {
mPlugins.put(info.getAlias(), plugin);
}
}Overall, the article walks through the step‑by‑step initialization and plugin loading flow of RePlugin, illustrating how processes are registered, how IPC is set up, and how plugins are installed, synchronized, and made available across all processes.
360 Tech Engineering
Official tech channel of 360, building the most professional technology aggregation platform for the brand.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.