2. Process management
In fact, android system refers to process management, which is the management of the four components, because the other classes are basically some ordinary classes.
Of course, process management in droidplugin framework is also the management of four components. The process management in Android system is not discussed here.
The structure diagram of process management is as follows.
The construction methods of these classes are not discussed here, they are relatively simple.
Plugin Manager is a client, and the corresponding server is Iplugin Manager Impl, which is actually a Package Manager Service imitating android system.
Provide simple management services for plug-ins.
Generally, when calling Plugin Manager's method, that is to say, calling the corresponding method of Iplugin ManagerImpl directly.
Some methods call the MyActivityManagerService implementation.
ProcessItem is the internal class of RunningProcesList, which mainly stores some component-related information.
2.1 activity
Or the performLaunchActivity method of ActivityThread, which calls the callActivityOnCreate method of mInstrumentation after the Activity is loaded.
if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); }
Of course, similar other methods will be invoked during acitivity's life cycle.
mInstrumentation.callActivityOnDestroy(r.activity);
Of course, some methods, Plugin Instrumentation, are also implemented, which is equivalent to managing the life cycle of an activity by itself.
2.1.1 Creation
The call ActivityOnCreate method call flow chart of PluginInstrumentation is as follows.

Part of the code for the callActivityOnCreate method is as follows.
onActivityCreated(activity);
The main logic of the onActivityCreated method is as follows.
1. Get ActivityInfo for replacement (host) and real (plug-in).
Intent targetIntent = activity.getIntent(); if (targetIntent != null) { ActivityInfo targetInfo = targetIntent.getParcelableExtra(Env.EXTRA_TARGET_INFO); ActivityInfo stubInfo = targetIntent.getParcelableExtra(Env.EXTRA_STUB_INFO);
2. Call the onActivtyCreate method of RunningActivities.
RunningActivities.onActivtyCreate(activity, targetInfo, stubInfo);
3. Call the onActivityCreated method of Plugin Manager.
PluginManager.getInstance().onActivityCreated(stubInfo, targetInfo);
The onActivty Create method of Running Activities is as follows.
public static void onActivtyCreate(Activity activity, ActivityInfo targetActivityInfo, ActivityInfo stubActivityInfo) { synchronized (mRunningActivityList) { RunningActivityRecord value = new RunningActivityRecord(activity, targetActivityInfo, stubActivityInfo, findMaxIndex() + 1); mRunningActivityList.put(activity, value); if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE) { mRunningSingleStandardActivityList.put(value.index, value); } else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { mRunningSingleTopActivityList.put(value.index, value); } else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { mRunningSingleTaskActivityList.put(value.index, value); } else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { mRunningSingleInstanceActivityList.put(value.index, value); } } }
Create Running activity Record object, Running activity Record is the internal class of Running Activities, which mainly records information about a pair of hosts and plug-in activities.
Then, according to the activation mode of activity, they are put into different hash tables.
private static Map<Activity, RunningActivityRecord> mRunningActivityList = new HashMap<>(); private static Map<Integer, RunningActivityRecord> mRunningSingleStandardActivityList = new HashMap<>(); private static Map<Integer, RunningActivityRecord> mRunningSingleTopActivityList = new HashMap<>(); private static Map<Integer, RunningActivityRecord> mRunningSingleTaskActivityList = new HashMap<>(); private static Map<Integer, RunningActivityRecord> mRunningSingleInstanceActivityList = new HashMap<>();
The mRunning activity List records all the started activities, and the other four variables record the activities of the corresponding startup mode.
Call the onActivityCreated method of Plugin Manager and look directly at the onActivityCreated method of Iplugin ManagerImpl.
public void onActivityCreated(ActivityInfo stubInfo, ActivityInfo targetInfo) throws RemoteException { mActivityManagerService.onActivityCreated(Binder.getCallingPid(), Binder.getCallingUid(), stubInfo, targetInfo); }
First, the pid and uid of the process in which the component is located are obtained, and then the onActivityCreated method of MyActivityManagerService is invoked.
public void onActivityCreated(int callingPid, int callingUid, ActivityInfo stubInfo, ActivityInfo targetInfo) { mRunningProcessList.addActivityInfo(callingPid, callingUid, stubInfo, targetInfo); }
Call RunningProcessList's addActivityInfo method directly, as follows.
void addActivityInfo(int pid, int uid, ActivityInfo stubInfo, ActivityInfo targetInfo) { ProcessItem item = items.get(pid); if (TextUtils.isEmpty(targetInfo.processName)) { targetInfo.processName = targetInfo.packageName; } if (item == null) { item = new ProcessItem();//Constructing ProcessItem objects item.pid = pid;//Entering id item.uid = uid;//User id items.put(pid, item); } item.stubProcessName = stubInfo.processName; if (!item.pkgs.contains(targetInfo.packageName)) { item.pkgs.add(targetInfo.packageName); } item.targetProcessName = targetInfo.processName; item.addActivityInfo(stubInfo.name, targetInfo); }
The main idea is to construct an internal class ProcessItem object and assign variables. In fact, a process id corresponds to a ProcessItem object.
The ProcessItem object is then put into the items hash table. In this way, if the IDs of different components are the same, you can correspond to a ProcessItem object without creating it every time.
Finally, the addActivityInfo method of ProcessItem is called as follows.
private void addActivityInfo(String stubActivityName, ActivityInfo info) { if (!targetActivityInfos.containsKey(info.name)) { targetActivityInfos.put(info.name, info); } //pkgs if (!pkgs.contains(info.packageName)) { pkgs.add(info.packageName); } //stub map to activity info Set<ActivityInfo> list = activityInfosMap.get(stubActivityName); if (list == null) { list = new TreeSet<ActivityInfo>(sComponentInfoComparator); list.add(info); activityInfosMap.put(stubActivityName, list); } else { list.add(info); } }
Both add information to the hash table. The seven hash tables of Process Item are as follows.
1. The four components of a plug-in correspond to the package name. Generally, a plug-in corresponds to a package name.
private List<String> pkgs = new ArrayList<String>(1);
2. The running plug-in ActivityInfo
//key=ActivityInfo.name, value = ActivityInfo of the plug-in, private Map<String, ActivityInfo> targetActivityInfos = new HashMap<String, ActivityInfo>(4);
3. The running plug-in ProviderInfo
//key=ProviderInfo.authority, value = ProviderInfo for plug-ins private Map<String, ProviderInfo> targetProviderInfos = new HashMap<String, ProviderInfo>(1);
4. The running plug-in ServiceInfo
//key=ServiceInfo.name, value = ServiceInfo for plug-ins private Map<String, ServiceInfo> targetServiceInfos = new HashMap<String, ServiceInfo>(1);
5. Mapping of running plug-in ActivityInfo to proxy ActivityInfo
//key = proxy ActivityInfo.name, value = plug-in ActiveInfo. name, private Map<String, Set<ActivityInfo>> activityInfosMap = new HashMap<String, Set<ActivityInfo>>(4);
6. Mapping between running plug-in ProviderInfo and proxy ProviderInfo
//key = proxy ProviderInfo.authority, value = plug-in ProviderInfo.authority, private Map<String, Set<ProviderInfo>> providerInfosMap = new HashMap<String, Set<ProviderInfo>>(4);
7. Mapping of running plug-in ServiceInfo to proxy ServiceInfo
//key = proxy ServiceInfo.name, value = plug-in ServiceInfo.name, private Map<String, Set<ServiceInfo>> serviceInfosMap = new HashMap<String, Set<ServiceInfo>>(4);
What you can see is that there is no hash table for broadcasting, because broadcasting is managed directly and systematically.
2.1.2 OnDestroy
The call Activity On Destroy method of Plugin Instrumentation is as follows.
public void callActivityOnDestroy(Activity activity) { if (mTarget != null) { mTarget.callActivityOnDestroy(activity); } else { super.callActivityOnDestroy(activity); } RunningActivities.onActivtyDestory(activity); if (enable) { try { onActivityDestory(activity); } catch (RemoteException e) { Log.e(TAG, "callActivityOnDestroy:onActivityDestory", e); } } }
First, the onActivty Destory method of RunningActivities is called, which is in conjunction with onActivty Create.
public static void onActivtyDestory(Activity activity) { synchronized (mRunningActivityList) { RunningActivityRecord value = mRunningActivityList.remove(activity); if (value != null) { ActivityInfo targetActivityInfo = value.targetActivityInfo; if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE) { mRunningSingleStandardActivityList.remove(value.index); } else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { mRunningSingleTopActivityList.remove(value.index); } else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { mRunningSingleTaskActivityList.remove(value.index); } else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { mRunningSingleInstanceActivityList.remove(value.index); } } } }
The onActivity Destory method is as follows.
private void onActivityDestory(Activity activity) throws RemoteException { Intent targetIntent = activity.getIntent(); if (targetIntent != null) { ActivityInfo targetInfo = targetIntent.getParcelableExtra(Env.EXTRA_TARGET_INFO); ActivityInfo stubInfo = targetIntent.getParcelableExtra(Env.EXTRA_STUB_INFO); if (targetInfo != null && stubInfo != null) { PluginManager.getInstance().onActivityDestory(stubInfo, targetInfo); } } }
The invocation process of onActivityCreated is exactly the same. The call flow chart is as follows.

The onActivity Destory method of MyActivityManagerService is as follows.
public void onActivityDestory(int callingPid, int callingUid, ActivityInfo stubInfo, ActivityInfo targetInfo) { mRunningProcessList.removeActivityInfo(callingPid, callingUid, stubInfo, targetInfo); runProcessGC(); }
ProcessItem's removeActivityInfo method is the opposite of the addActivityInfo method, which is the process of deleting elements from a hash table.
void removeActivityInfo(String stubActivityName, ActivityInfo targetInfo) { targetActivityInfos.remove(targetInfo.name); //remove form map if (stubActivityName == null) { for (Set<ActivityInfo> set : activityInfosMap.values()) { set.remove(targetInfo); } } else { Set<ActivityInfo> list = activityInfosMap.get(stubActivityName); if (list != null) { list.remove(targetInfo); } } updatePkgs(); }
The runProcess GC method mainly collects process garbage. Let's discuss it later.