How RePlugin Manages Processes and Loads Plugins: A Deep Source Code Walkthrough
This article dissects RePlugin's process management and plugin loading mechanisms from a source‑code perspective, detailing the startup sequence, framework configuration, IPC initialization, PMF setup, plugin installation flow, and how plugins are registered and synchronized across processes.
This article analyzes RePlugin's process management mechanism from the source‑code level, focusing on the process startup and plugin loading procedures.
Process Startup
The system first calls RePluginApplication.attachBaseContext, which then invokes RePlugin.App.attachBaseContext.
public static void attachBaseContext(Application app, RePluginConfig config) {
if (sAttached) {
if (LogDebug.LOG) {
LogDebug.d(TAG, "attachBaseContext: Already called");
}
return;
}
RePluginInternal.init(app);
sConfig = config;
sConfig.initDefaults(app);
IPC.init(app);
// additional initialization steps omitted for brevity
sAttached = true;
}The method performs several key steps:
Initializes the internal framework via RePluginInternal.init(app).
Sets up the framework configuration.
Initializes the IPC process communication class, configuring process name, PID, package name, persistent‑process name, UI‑process flag, and persistent‑process flag.
Initializes the Plugin Manager Framework (PMF) and calls PMF.callAttach().
Key Initialization Methods
RePluginInternal.init() simply stores the application context for later use:
static void init(Application app) {
sAppContext = app;
}Framework configuration assigns the provided RePluginConfig to sConfig and calls sConfig.initDefaults(app).
IPC.init() sets up inter‑process communication attributes:
public static void init(Context context) {
sCurrentProcess = SysUtils.getCurrentProcessName();
sCurrentPid = Process.myPid();
sPackageName = context.getApplicationInfo().packageName;
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.init() prepares the plugin manager and patches the host class loader:
public static final void init(Application application) {
setApplicationContext(application);
PluginManager.init(application);
sPluginMgr = new PmBase(application);
sPluginMgr.init();
Factory.sPluginManager = PMF.getLocal();
Factory2.sPLProxy = PMF.getInternal();
PatchClassLoaderUtils.patch(application);
}PMF.callAttach() loads plugins into the process:
final void callAttach() {
mClassLoader = PmBase.class.getClassLoader();
for (Plugin p : mPlugins.values()) {
p.attach(mContext, mClassLoader, mLocal);
}
if (PluginManager.isPluginProcess()) {
Plugin p = mPlugins.get(mDefaultPluginName);
if (p != null) {
boolean rc = p.load(Plugin.LOAD_APP, true);
if (rc) {
mDefaultPlugin = p;
mClient.init(p);
}
}
}
}Plugin Manager Initialization
PluginManager.init(Context context)sets the current process UID and plugin‑process index, applying specific rules for UI, persistent, loader, and custom processes.
public void init(Context context) {
// initialize sUid and sPluginProcessIndex based on process type
// UI process -> -1, Persistent -> -2, loader0~1 -> 0~1, p1~p3 -> -100~-98
}PmBase Core Functions
newPluginFound() updates the plugin tables and notifies the process:
final void newPluginFound(PluginInfo info, boolean persistNeedRestart) {
PluginTable.updatePlugin(info);
insertNewPlugin(info);
PluginStatusController.setStatus(info.getName(), info.getVersion(), PluginStatusController.STATUS_OK);
// broadcast new plugin intent
}insertNewPlugin() adds a new plugin to the internal map, handling version comparison and persistence:
final void insertNewPlugin(PluginInfo info) {
if (RePlugin.getConfig().getCallbacks().isPluginBlocked(info)) return;
Plugin p = mPlugins.get(info.getPackageName());
if (p != null && p.isInitialized()) return; // already loaded
mNeedRestart = true;
Plugin plugin = Plugin.build(info);
plugin.attach(mContext, mClassLoader, mLocal);
putPluginObject(info, plugin);
}putPluginObject() stores the plugin in the map and, if running in the persistent process, updates the plugins_up shared‑preferences 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);
}
}Plugin Installation Flow
The installation starts with RePlugin.install(String path), which validates the file and delegates to MP.pluginDownloaded(path).
public static PluginInfo install(String path) {
// validate file
return MP.pluginDownloaded(path);
} MP.pluginDownloaded(String path)handles lock files for p‑n plugins, calls the host process if needed, and returns a PluginInfo object.
PluginInfo info = PluginProcessMain.getPluginHost().pluginDownloaded(path);
if (info != null) {
RePlugin.getConfig().getEventCallbacks().onInstallPluginSucceed(info);
}
return info;In the persistent process, PmHostSvc.pluginDownloaded() determines the plugin type (p‑n or APK) and forwards the request to the appropriate installer.
if (fn.startsWith("p-n-") || fn.startsWith("v-plugin-") || fn.startsWith("plugin-s-") || fn.startsWith("p-m-")) {
pi = pluginDownloadedForPn(path);
} else {
pi = mManager.getService().install(path);
}
if (pi != null) {
syncInstalledPluginInfo2All(pi);
}
return pi;syncInstalledPluginInfo2All() synchronizes the new plugin info to all processes via a local broadcast.
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);Process ID Mapping
RePlugin assigns the following IDs to processes:
UI process: -1
Persistent process: -2
loader0~loader1: 0~1
p1~p3: -100~-98
Understanding these IDs is essential for interpreting the plugin‑process index values used throughout the framework.
Overall, the article provides a step‑by‑step walkthrough of how RePlugin initializes its environment, manages process information, installs plugins, and keeps all processes in sync, giving developers a clear view of the inner workings of this Android plugin framework.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Qizhuo Club
360 Mobile tech channel sharing practical experience and original insights from 360 Mobile Security and other teams across Android, iOS, big data, AI, and more.
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.
