zoukankan      html  css  js  c++  java
  • 安卓高手之路之ClassLoader(总结篇)

    安卓高手之路之ClassLoader(总结篇) - 修补C++ - ITeye技术网站

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

    Java代码  收藏代码
    1. const char* envStr = getenv("CLASSPATH");  
    2.   if (envStr != NULL) {  
    3.       gDvm.classPathStr = strdup(envStr);  
    4.   } else {  
    5.       gDvm.classPathStr = strdup(".");  
    6.   }  
    7.   envStr = getenv("BOOTCLASSPATH");  
    8.   if (envStr != NULL) {  
    9.       gDvm.bootClassPathStr = strdup(envStr);  
    10.   } else {  
    11.       gDvm.bootClassPathStr = strdup(".");  
    12.   }  
      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

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

    Cpp代码  收藏代码
    1. static jclass FindClass(JNIEnv* env, const char* name) {  
    2.     ScopedJniThreadState ts(env);  
    3.   
    4.     const Method* thisMethod = dvmGetCurrentJNIMethod();  
    5.     assert(thisMethod != NULL);  
    6.   
    7.     Object* loader;  
    8.     Object* trackedLoader = NULL;  
    9.     if (ts.self()->classLoaderOverride != NULL) {  
    10.         /* hack for JNI_OnLoad */  
    11.         assert(strcmp(thisMethod->name, "nativeLoad") == 0);  
    12.         loader = ts.self()->classLoaderOverride;  
    13.     } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||  
    14.                thisMethod == gDvm.methDalvikSystemNativeStart_run) {  
    15.         /* start point of invocation interface */  
    16.         if (!gDvm.initializing) {  
    17.             loader = trackedLoader = dvmGetSystemClassLoader();  
    18.         } else {  
    19.             loader = NULL;  
    20.         }  
    21.     } else {  
    22.         loader = thisMethod->clazz->classLoader;  
    23.     }  
    24.   
    25.     char* descriptor = dvmNameToDescriptor(name);  
    26.     if (descriptor == NULL) {  
    27.         return NULL;  
    28.     }  
    29.     ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);  
    30.     free(descriptor);  
    31.   
    32.     jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);  
    33.     dvmReleaseTrackedAlloc(trackedLoader, ts.self());  
    34.     return jclazz;  
    35. }  
    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

           

    Java代码  收藏代码
    1. @Override  
    2.   public ClassLoader getClassLoader() {  
    3.       return mPackageInfo != null ?  
    4.               mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();  
    5.   }  
      @Override
        public ClassLoader getClassLoader() {
            return mPackageInfo != null ?
                    mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
        }
    Java代码  收藏代码
    1. package android.app;  
    2.   
    3. import dalvik.system.PathClassLoader;  
    4.   
    5. import java.util.HashMap;  
    6. import java.util.Map;  
    7.   
    8. class ApplicationLoaders  
    9. {  
    10.     public static ApplicationLoaders getDefault()  
    11.     {  
    12.         return gApplicationLoaders;  
    13.     }  
    14.   
    15.     public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent)  
    16.     {  
    17.         /* 
    18.          * This is the parent we use if they pass "null" in.  In theory 
    19.          * this should be the "system" class loader; in practice we 
    20.          * don't use that and can happily (and more efficiently) use the 
    21.          * bootstrap class loader. 
    22.          */  
    23.         ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();  
    24.   
    25.         synchronized (mLoaders) {  
    26.             if (parent == null) {  
    27.                 parent = baseParent;  
    28.             }  
    29.   
    30.             /* 
    31.              * If we're one step up from the base class loader, find 
    32.              * something in our cache.  Otherwise, we create a whole 
    33.              * new ClassLoader for the zip archive. 
    34.              */  
    35.             if (parent == baseParent) {  
    36.                 ClassLoader loader = mLoaders.get(zip);  
    37.                 if (loader != null) {  
    38.                     return loader;  
    39.                 }  
    40.       
    41.                 PathClassLoader pathClassloader =  
    42.                     new PathClassLoader(zip, libPath, parent);  
    43.                   
    44.                 mLoaders.put(zip, pathClassloader);  
    45.                 return pathClassloader;  
    46.             }  
    47.   
    48.             return new PathClassLoader(zip, parent);  
    49.         }  
    50.     }  
    51.   
    52.     private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>();  
    53.   
    54.     private static final ApplicationLoaders gApplicationLoaders  
    55.         = new ApplicationLoaders();  
    56. }  
    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。

  • 相关阅读:
    深入理解 CSS3 弹性盒布局模型
    【css基础】文本对齐,水平对齐,垂直对齐
    使用百度地图API进行坐标系转换
    dtgrid 手动条件删除表格中的某一行
    短时间生成大量不重复随机数字
    Android与.Net交互模拟用户屏幕操作添加APN和网络4G/3G切换
    (三)SpringBoot定义统一返回result对象
    (二)SpringBoot整合常用框架Druid连接池
    (一)搭建自己的SpringBoot后台框架整合MyBatis
    插件-鼠标或手指滑动事件
  • 原文地址:https://www.cnblogs.com/seven1979/p/4369613.html
Copyright © 2011-2022 走看看