Android中的类装载器DexClassLoader

2023-10-06 16:42

本文主要是介绍Android中的类装载器DexClassLoader,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在java中,有个概念叫做“类加载器”(ClassLoader),它的作用就是动态的装载Class文件。标准的java sdk中有一个
ClassLoader类,借助这个类可以装载想要的Class文件,每个ClassLoader对象在初始化时必须制定Class文件的路径。
可能有人会问,在写程序的时候不是有import关键字可以引用制定的类吗?为何还要使用这个类加载器呢?
原因其实是这样的,使用import关键字引用的类必须符合以下两个条件
  •    类文件必须在本地,当程序运行时需要次类时,这时类装载器会自动装载该类,程序员不需要关注此过程。
  •    编译的时候必须有这个类文件,否则编译不通过。
如果想让程序在运行的时候动态调用怎么办呢?用import显示是不符合上面的两种要求的。此时ClassLoader就派上用场了。
关于java的Classloader的装载机制请参考此链接  http://www.iteye.com/topic/83978,最好到网上自行搜索一下。
http://www.artima.com/insidejvm/ed2/《Inside the Java Virtural Machine》
对于 android应用程序,本质上使用的是java开发,使用标准的java编译器编译出Class文件,和普通的java开发不同的
地方是把class文件再重新打包成dex类型的文件,这种重新打包会对Class文件内部的各种函数表、变量表等进行优化,
最终产生了dex文件。dex文件是一种经过android打包工具优化后的Class文件,因此加载这样特殊的Class文件就需要特殊的类装载器,
所以android中提供了DexClassLoader类。
类装载器DexClassLoader类结构
继承关系:
    

A class loader that loads classes from .jar and .apk files containing a classes.dex entry. This can be used to execute code not installed as part of an application.

This class loader requires an application-private, writable directory to cache optimized classes. Use Context.getDir(String, int) to create such a directory:

<code style="line-height: 14px;"><span class="typ" style="color: rgb(102, 0, 102);">File</span><span class="pln" style="color: rgb(0, 0, 0);"> dexOutputDir </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getDir</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="str" style="color: rgb(136, 0, 0);">"dex"</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0</span><span class="pun" style="color: rgb(102, 102, 0);">);</span></code>

Do not cache optimized classes on external storage. External storage does not provide access controls necessary to protect your application from code injection attacks.

翻译:这个类加载器用来从.jar和.apk类型的文件内部加载classes.dex文件。通过这种方式可以用来执行非安装的程序代码,作为程序的一部分进行运行。
这个装载类需要一个程序私有的,可写的文件目录去存放优化后的classes文件。通过Contexct.getDir(String, int)来创建

这个目录:

File  dexOutputDir  =  context . getDir ( "dex" ,   0 );

不要把优化优化后的classes文件存放到外部存储设备上,防代码注入攻击。


这个类只有一个构造函数:
public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)
Added in  API level 3

Creates a DexClassLoader that finds interpreted and native code. Interpreted classes are found in a set of DEX files contained in Jar or APK files.

创建一个DexClassLoader用来找出指定的类和本地代码(c/c++代码)。用来解释执行在DEX文件中的class文件。

路径的分隔符使用通过System的属性 path.separator 获得 :.

String separeater = System.getProperty("path.separtor");

类装载器DexClassLoader的具体使用

这个类的使用过程基本是这样:
  • 通过PacageMangager获得指定的apk的安装的目录,dex的解压缩目录,c/c++库的目录
  • 创建一个 DexClassLoader实例
  • 加载指定的类返回一个Class
  • 然后使用反射调用这个Class
下面是代码部分,代码参考自《Android内核剖析》(作者柯元旦,这本书不错,推荐阅读):
[html]  view plain copy
  1. @SuppressLint("NewApi") private void useDexClassLoader(){  
  2.     //创建一个意图,用来找到指定的apk  
  3.     Intent intent = new Intent("com.suchangli.android.plugin", null);  
  4.     //获得包管理器  
  5.     PackageManager pm = getPackageManager();  
  6.     List<ResolveInfo> resolveinfoes =  pm.queryIntentActivities(intent, 0);  
  7.     //获得指定的activity的信息  
  8.     ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;  
  9.       
  10.     //获得包名  
  11.     String pacageName = actInfo.packageName;  
  12.     //获得apk的目录或者jar的目录  
  13.     String apkPath = actInfo.applicationInfo.sourceDir;  
  14.     //dex解压后的目录,注意,这个用宿主程序的目录,android中只允许程序读取写自己  
  15.     //目录下的文件  
  16.     String dexOutputDir = getApplicationInfo().dataDir;  
  17.       
  18.     //native代码的目录  
  19.     String libPath = actInfo.applicationInfo.nativeLibraryDir;  
  20.     //创建类加载器,把dex加载到虚拟机中  
  21.     DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,  
  22.             this.getClass().getClassLoader());  
  23.       
  24.     //利用反射调用插件包内的类的方法  
  25.       
  26.     try {  
  27.         Class<?> clazz = calssLoader.loadClass(pacageName+".Plugin1");  
  28.           
  29.         Object obj = clazz.newInstance();  
  30.         Class[] param = new Class[2];  
  31.         param[0] = Integer.TYPE;  
  32.         param[1] = Integer.TYPE;  
  33.           
  34.         Method method = clazz.getMethod("function1", param);  
  35.           
  36.         Integer ret = (Integer)method.invoke(obj, 1,12);  
  37.           
  38.         Log.i("Host", "return result is " + ret);  
  39.           
  40.     } catch (ClassNotFoundException e) {  
  41.         e.printStackTrace();  
  42.     } catch (InstantiationException e) {  
  43.         e.printStackTrace();  
  44.     } catch (IllegalAccessException e) {  
  45.         e.printStackTrace();  
  46.     } catch (NoSuchMethodException e) {  
  47.         e.printStackTrace();  
  48.     } catch (IllegalArgumentException e) {  
  49.         e.printStackTrace();  
  50.     } catch (InvocationTargetException e) {  
  51.         e.printStackTrace();  
  52.     }  
  53.    }  
Plugin1.apk中的一个类:
[html]  view plain copy
  1. package com.suchangli.plugin1;  
  2.   
  3. public class Plugin1 {  
  4.     public int function1(int a, int b){  
  5.           
  6.         return a+b;  
  7.     }  
  8. }  


Log输出的结果:
注意要在Plugin1中的清单文件的一个activity中添加一个如下的action,这个action必须是宿主和插件约定好的。
源代码:
通过以上代码就可以访问另一个apk中的代码了,一个比较麻烦的地方就是必须用反射才能调用方法,
有没不用反射也可以调用方法方式呢?当然有,通过接口。

这篇关于Android中的类装载器DexClassLoader的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/153518

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 :frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可,不过需要覆盖所有目录下的图片。 由于是静态修改,则需要make一下,重新编译。 2、方法二Overlay方式 由于上述方法有很大缺点,修改多了之后容易遗忘自己修改哪些文件,为此我们采用另外一种方法,使用Overlay方式。