组件加载
来源:互联网 发布:如何下载网站的源码 编辑:程序博客网 时间:2024/04/20 03:56
1,组件加载
1.1 四大组件加载
1,activity加载方法
还是在ActivityThread的performLaunchActivity方法中,匹配完成之后,
ComponentName component = r.intent.getComponent();if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component);}•••Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
通过ClassLoader加载了需要的Activity类并通过反射调用构造函数创建出了Activity对象。
如果Activity组件存在于独立于宿主程序的文件之中,系统的ClassLoader怎么知道去哪里加载呢?
2,service加载方法
Startservice方法最后,在ActivityThread的handleCreateService方法中,
java.lang.ClassLoader cl = packageInfo.getClassLoader();service = (Service) cl.loadClass(data.info.name).newInstance();
同样的, 通过ClassLoader加载了需要的Service类并通过反射调用构造函数创建出了Service对象。
Bindservice 方法最后在ActivityThread的handleBindService方法中,
data.intent.setExtrasClassLoader(s.getClassLoader());
3, BroadcastReceiver加载方法
在ActivityThread的handleReceiver方法中,
java.lang.ClassLoader cl = packageInfo.getClassLoader();data.intent.setExtrasClassLoader(cl);data.intent.prepareToEnterProcess();data.setExtrasClassLoader(cl);receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
4, ContentProvider加载方法
在ActivityThread的installProvider方法中,
final java.lang.ClassLoader cl = c.getClassLoader();localProvider = (ContentProvider)cl. loadClass(info.name).newInstance();provider = localProvider.getIContentProvider();
c为Context(进程上下文)对象。
首先,这些组价都独立于宿主程序的文件之中, 要使存在于独立文件或者网络中的插件被成功启动,就需要解决插件类加载的问题。
1.2 框架加载过程
1,activity加载
acitvity 启动的时候必然会调用PluginCallback.java的handleLaunchActivity方法,当然,首先匹配,然后加载匹配的acitvity。加载activity代码如下,
ResolveInfo resolveInfo = mHostContext.getPackageManager().resolveActivity(stubIntent, 0);ActivityInfo stubActivityInfo = resolveInfo != null ? resolveInfo.activityInfo : null;•••PluginManager.getInstance().reportMyProcessName(stubActivityInfo.processName, targetActivityInfo.processName, targetActivityInfo.packageName); //组件的进程管理•••PluginProcessManager.preLoadApk(mHostContext, targetActivityInfo);
2,service加载
同样的, service在ServcesManager的handleCreateServiceOne方法完成匹配,匹配之后就是加载,
ResolveInfo resolveInfo = hostContext.getPackageManager().resolveService(stubIntent, 0);ServiceInfo stubInfo = resolveInfo != null ? resolveInfo.serviceInfo : null;•••PluginManager.getInstance().reportMyProcessName(stubInfo.processName, info.processName, info.packageName); //组件的进程管理PluginProcessManager.preLoadApk(hostContext, info);
3, BroadcastReceiver加载
BroadcastReceiver和其他三个组件有些不同,插件中的BroadcastReceiver最后都是以静态的方法注册到系统里面去了,
所以加载和进程管理都是由系统进行。
4, ContentProvider加载
String authority = getMyAuthority();stubInfo = getContext().getPackageManager().resolveContentProvider(authority, 0);targetInfo = PluginManager.getInstance().resolveContentProvider(targetAuthority, 0);•••PluginManager.getInstance().reportMyProcessName(stubInfo.processName, targetInfo.processName, targetInfo.packageName); //组件的进程管理•••PluginProcessManager.preLoadApk(getContext(), targetInfo);
除了BroadcastReceiver以外,其他三个组件都是调用PluginProcessManager的preLoadApk方法进行。
1.3 ClassLoader Hook
插件的加载主要是通过ClassLoader完成。ActivityThread中mPackages变量保存着整个系统中所有apk对应的LoadedApk,
一般一个apk对应一个LoadedApk, LoadedApk主要负责apk的加载。mPackages变量定义如下,
final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>();
加载的时候调用LoadedApk的getClassLoader方法mClassLoader变量, mClassLoader变量定义如下,
private ClassLoader mClassLoader;
所以,如果想要将mClassLoader替换成自己的ClassLoader,只需要Hook 这个mClassLoader变量就可以,这样就可以使用自己的ClassLoader来加载插件了。
PluginProcessManager的preLoadApk方法主要逻辑如下,
1,获取当前的ActivityThread的mPackages变量,
Object object = ActivityThreadCompat.currentActivityThread();if (object != null) { Object mPackagesObj = FieldUtils.readField(object, "mPackages");
2,通过通过ActivityThread的getPackageInfoNoCheck方法创建自己的LoadedApk对象
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { loadedApk = MethodUtils.invokeMethod(object, "getPackageInfoNoCheck", pluginInfo.applicationInfo, CompatibilityInfoCompat.DEFAULT_COMPATIBILITY_INFO()); } else { loadedApk = MethodUtils.invokeMethod(object, "getPackageInfoNoCheck", pluginInfo.applicationInfo); }
3,将loadedApk对象添加到sPluginLoadedApkCache中,进行管理。
sPluginLoadedApkCache.put(pluginInfo.packageName, loadedApk);
同样的,一个插件对应一个loadedApk对象。
4,获取插件的相关路径信息,
String optimizedDirectory = PluginDirHelper.getPluginDalvikCacheDir(hostContext, pluginInfo.packageName);String libraryPath = PluginDirHelper.getPluginNativeLibraryDir(hostContext, pluginInfo.packageName);String apk = pluginInfo.applicationInfo.publicSourceDir;
5,构造PluginClassLoader对象,
ClassLoader classloader = null;try { classloader = new PluginClassLoader(apk, optimizedDirectory, libraryPath, ClassLoader.getSystemClassLoader());} catch (Exception e) { }if(classloader==null){ PluginDirHelper.cleanOptimizedDirectory(optimizedDirectory); classloader = new PluginClassLoader(apk, optimizedDirectory, libraryPath, ClassLoader.getSystemClassLoader());}
当然,在构造PluginClassLoader对象的是就加载插件, 详细过程请见ClassLoader机制。
6,将loadedApk的mClassLoader对象设置成PluginClassLoader对象。
synchronized (loadedApk) { FieldUtils.writeDeclaredField(loadedApk, "mClassLoader", classloader); } sPluginClassLoaderCache.put(pluginInfo.packageName, classloader);Thread.currentThread().setContextClassLoader(classloader);
并且将PluginClassLoader对象放入sPluginClassLoaderCache变量中。
sPluginLoadedApkCache和sPluginClassLoaderCache定义如下,
private static Map<String, ClassLoader> sPluginClassLoaderCache = new WeakHashMap<String, ClassLoader>(1); private static Map<String, Object> sPluginLoadedApkCache = new WeakHashMap<String, Object>(1);
存放在插件对应的loadedApk和ClassLoader 对象。
PluginClassLoader比较简单,继承于DexClassLoader。详细的ClassLoader机制在此就不论述了。
- 组件加载
- Fresco图片加载组件
- 组件交互及动态组件加载
- delphi7 如何加载com组件
- Mozilla研究-组件加载机制
- ExtJS 4动态加载组件
- c#动态加载com组件
- SWING 组件加载图片方法
- EnhancedEditor 不可加载编辑器组件
- web.xml组件加载顺序
- Ext自动加载自定义组件
- Android ImageLoader组件加载图片
- Loader组件的动态加载
- web.xml组件加载顺序
- web.xml组件加载顺序
- web.xml 组件加载顺序
- vue 页面加载进度条组件
- web.xml 组件加载顺序
- Apache Hive 入门
- 题目1055:数组逆置
- C开发lua模块(一) --- 虚拟栈和基本代码结构
- Java Web--增删改查之一界面jsp的操作部分
- HDU 5791 题解
- 组件加载
- Spring对bean的装配机制(一)——隐式自动装配
- java实现一个简单的登录界面
- pandas 解析json文件为DataFrame的三种方式以及其灵活度和效率的比较
- ROS之tf空间坐标变换浅析 (二)
- ThreadLocal
- 页面跳转
- Java Web--增删改查之二界面后台java代码
- Stream 中Collectors 的用法