安卓系统对ClassLoader的设计可谓别有用心。前面分析过,赋值的地方如下:

  const char* envStr = getenv("CLASSPATH");
if (envStr != NULL) {
gDvm.classPathStr = strdup(envStr);
} else {
gDvm.classPathStr = strdup(".");
}
envStr = getenv("BOOTCLASSPATH");
if (envStr != NULL) {
gDvm.bootClassPathStr = strdup(envStr);
} else {
gDvm.bootClassPathStr = strdup(".");
}

分为三级:

Boot      与BOOTCLASSPATH对应

System  与CLASSPATH对应。

App       与应用程序包对应。

在应用程序里面,Context控制着一个ClassLoader,通过建立不同的ClassLoader,对外界控制着对APK包的访问权限。

主要有如下几种:

/**
     * Flag for use with {@link #createPackageContext}: include the application
     * code with the context.  This means loading code into the caller's
     * process, so that {@link #getClassLoader()} can be used to instantiate
     * the application's classes.  Setting this flags imposes security
     * restrictions on what application context you can access; if the
     * requested application can not be safely loaded into your process,
     * java.lang.SecurityException will be thrown.  If this flag is not set,
     * there will be no restrictions on the packages that can be loaded,
     * but {@link #getClassLoader} will always return the default system
     * class loader.
     */
    public static final int CONTEXT_INCLUDE_CODE = 0x00000001;

/**
     * Flag for use with {@link #createPackageContext}: ignore any security
     * restrictions on the Context being requested, allowing it to always
     * be loaded.  For use with {@link #CONTEXT_INCLUDE_CODE} to allow code
     * to be loaded into a process even when it isn't safe to do so.  Use
     * with extreme care!
     */
    public static final int CONTEXT_IGNORE_SECURITY = 0x00000002;

/**
     * Flag for use with {@link #createPackageContext}: a restricted context may
     * disable specific features. For instance, a View associated with a restricted
     * context would ignore particular XML attributes.
     */
    public static final int CONTEXT_RESTRICTED = 0x00000004;

1.ClassLoader如其名,就是加载class用的。

2.一开始的时候,是通过dalvik/vm/Jni.cpp中的FindClass函数来找类的。

NativeStart是一个假类,里面的main是java堆栈的root。

第一。系统启动

因为这段代码是C++的代码,那么可以肯定一定是java(或者NativeStart这个假main函数)调用过来的。

具体谁调用过来的,这里做了个判断:

如果是NativeStart.main:

这个时候要进行初始化判断,有可能vm还没有进行初始化。

如果是System.nativeload

这个时候,就用classLoaderOverride

如果是其他:

就是 thisMethod->clazz->classLoader 也就是 加载这段代码的classloader

分别进入了三个不同的分支。

static jclass FindClass(JNIEnv* env, const char* name) {
ScopedJniThreadState ts(env);
const Method* thisMethod = dvmGetCurrentJNIMethod();
assert(thisMethod != NULL);
Object* loader;
Object* trackedLoader = NULL;
if (ts.self()->classLoaderOverride != NULL) {
/* hack for JNI_OnLoad */
assert(strcmp(thisMethod->name, "nativeLoad") == 0);
loader = ts.self()->classLoaderOverride;
} else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
thisMethod == gDvm.methDalvikSystemNativeStart_run) {
/* start point of invocation interface */
if (!gDvm.initializing) {
loader = trackedLoader = dvmGetSystemClassLoader();
} else {
loader = NULL;
}
} else {
loader = thisMethod->clazz->classLoader;
}
char* descriptor = dvmNameToDescriptor(name);
if (descriptor == NULL) {
return NULL;
}
ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
free(descriptor);
jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
dvmReleaseTrackedAlloc(trackedLoader, ts.self());
return jclazz;
}

这种classLoade是BootClassLoader.

第二 app启动。

app启动 通过socket完成。通过fork来创建一个子进程。这个时候ClassLoader是与Context有关的。

不同的Context对应不同的ClassLoader。这个ClassLoader是一个PathClassLoader

  @Override
public ClassLoader getClassLoader() {
return mPackageInfo != null ?
mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
}
package android.app;
import dalvik.system.PathClassLoader;
import java.util.HashMap;
import java.util.Map;
class ApplicationLoaders
{
public static ApplicationLoaders getDefault()
{
return gApplicationLoaders;
}
public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent)
{
/*
* This is the parent we use if they pass "null" in.  In theory
* this should be the "system" class loader; in practice we
* don't use that and can happily (and more efficiently) use the
* bootstrap class loader.
*/
ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
synchronized (mLoaders) {
if (parent == null) {
parent = baseParent;
}
/*
* If we're one step up from the base class loader, find
* something in our cache.  Otherwise, we create a whole
* new ClassLoader for the zip archive.
*/
if (parent == baseParent) {
ClassLoader loader = mLoaders.get(zip);
if (loader != null) {
return loader;
}
PathClassLoader pathClassloader =
new PathClassLoader(zip, libPath, parent);
mLoaders.put(zip, pathClassloader);
return pathClassloader;
}
return new PathClassLoader(zip, parent);
}
}
private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>();
private static final ApplicationLoaders gApplicationLoaders
= new ApplicationLoaders();
}

具体来讲ClassLoader.getSystemClassLoader() 返回的是一个PathClassLoader,而

ClassLoader.getSystemClassLoader().getParent() 返回的是一个BootClassLoader。

如果LoadedApk这个类在构造的时候,传入了个BootClassLoader或者null,那么就会执行
                PathClassLoader pathClassloader =
                    new PathClassLoader(zip, libPath, parent);
               
                mLoaders.put(zip, pathClassloader);
                return pathClassloader;
也就是说 把libPath进行了传入。

否则用如下构造函数执行

return new PathClassLoader(zip, parent);
可以看到,少了一个参数libPath,libPath是libjni。那么这个是什么意思呢?

经过看代码,默认LoadedAPK传入的loader是个null, 因此,会使用libPath进行构造。并且它的父Loader是BootClassLoader。那么什么时候传入的loader不是nul呢。用instrument的时候传入的不是null。

安卓高手之路之ClassLoader(总结篇)相关推荐

  1. 安卓高手之路之 ClassLoader

    我不喜欢那些泛泛而谈的去讲那些形而上学的道理,更不喜欢记那些既定的东西.靠记忆去弥补思考的人,容易陷入人云亦云的境地,最后必定被记忆所围困,而最终消亡的是创造力.希望这个高手之路系列能够记录我学习安卓 ...

  2. [置顶] 安卓高手之路之ClassLoader(二)

    因为ClassLoader一定与虚拟机的启动有关系,那么必须从Zygote的启动开始看代码.下面就分析一下这些代码,行数不多: int main(int argc, const char* const ...

  3. 安卓高手之路之ClassLoader(二)

    因为ClassLoader一定与虚拟机的启动有关系,那么必须从Zygote的启动开始看代码.下面就分析一下这些代码,行数不多: int main(int argc, const char* const ...

  4. 安卓高手之路之ClassLoader(四)

    显然,应用层的classLoader绝对不仅仅是一个systemclassloader那么简单.那么他一定是与PackageInfo连接起来的.而这个连接的纽带就是ContextImpl.Contex ...

  5. 安卓高手之路之ClassLoader(三)

    由于看C++和C代码看得很累,很辛苦.上一章终于解脱到java代码中来了. 第一个getClassLoader发生在main的preload方法中, public static void main(S ...

  6. 安卓高手之路之 GDI图形引擎篇

    1.底层C++ SufaceFlinger类图的静态结构  2.上层Java的调用流程. 首先,直接从WindowManagerService入手: public int relayoutWindow ...

  7. 安卓高手之路 图形系统(2)----------------基于Binder的架构思路)

    在学习安卓的时候最迷惑的就是Binder.图形框架的理解与Binder的理解分不开.前面一篇 [ 安卓高手之路之java层Binder 从代码角度分析了Java层Binder的实现原理.在C++层,这 ...

  8. 安卓高手之路 图形系统(4 Measure的算法)

    安卓高手之路 图形系统(4 Measure的算法) - 修补C++ - ITeye技术网站 Java代码   /** * Does the hard part of measureChildren:  ...

  9. 安卓高手之路之 图形系统之 图形框架(1)

    安卓图形系统理解起来并不容易.那是因为系统对于数据的封装非常多,图形模块与输入输出,应用程序管理等模块参杂在一起.让开发者很难摸清其中的脉络.下面先给出最简单的一张图.             这张图 ...

最新文章

  1. 1033 To Fill or Not to Fill (25 分)【难度: 难 / 知识点: 模拟 贪心】
  2. 菜鸟系列之C/C++经典试题(七)
  3. Spring JtaTransactionManager事务管理
  4. stephen boyd著王书宁译凸优化课后题答案
  5. win10 电脑扬声器显示未插入
  6. UVA - 1589 Xiangqi
  7. app做好后如何上线_自己做的app从做好到上架需要什么手续或过程?
  8. 【Rust精彩blog】Rust 中几个智能指针的异同与使用场景
  9. 苹果研发microLED暂难摆脱对三星的依赖
  10. 网络统考计算机实机操作,2020年国家开放大学电大考试《计算机应用基础》网络核心课形考网考作业试题及答案(完整版)(42页)-原创力文档...
  11. 某音漂亮小姐姐视频合集一键下载,想看就看!
  12. ffmpeg学习十二:滤镜(实现视频缩放,裁剪,水印等)
  13. 部门管理中非递归搜索部门以及所管辖下部门
  14. OUC2021秋-计算机网络-期末(回忆版)
  15. 信息学奥赛一本通 1278:【例9.22】复制书稿(book) | 洛谷 P1281 书的复制
  16. jquery创建css_如何使用jQuery和CSS创建万花筒
  17. 程序人生 - 车险到底哪家好、怎么选?三巨头对比,让你一目了然
  18. 【微课制作软件】Focusky教程 | 怎样摆正画布?
  19. 区块链是什么,是否是一个骗局或者是不是有弊端??
  20. Fate单机部署(docker版本)

热门文章

  1. vue 分享微信传参_vue 中使用微信分享接口(简单实用)
  2. linux安装metasploit,centos如何安装metasploit
  3. java语言的多态性及特点_Java中的方法的多态性有两种形式:( )和( )。_学小易找答案...
  4. linux halt函数,常用Linux命令 reboot halt shutdown passwd vlock exit等
  5. XP系统,无法创建新的网络连接
  6. nginx解析php
  7. php生成sitemap
  8. 怎样在不处理的情况下在ABBYY FineReader中添加图像
  9. JDK5 新特性之 可变参数的方法(2)---asList
  10. 体绘制(Volume Rendering)概述之4:光线投射算法(Ray Casting)实现流程和代码(基于CPU的实现)...