一种Android系统无感知应用安装升级的方法与流程

文档序号:15346463发布日期:2018-09-04 22:49阅读:326来源:国知局

本发明涉及移动终端应用领域,尤其涉及一种android系统无感知应用安装升级的方法。



背景技术:

一个android应用发布后如果突然出现bug需要紧急修复的话,普通的打包、发布、安装、升级流程很繁琐而且需要用户介入点击安装,效果很不好。因此免安装升级成为一个比较迫切的需求。免安装升级可以帮助我们在用户无感知的情况下修复应用存在的bug。

目前市面上此类热修复框架不少,比较有名的有支付宝的andfix,nuwa方案,微信的tinker热修复方案等。

支付宝的andfix采用的是native层hook的方案,主要是通过替换方法的方式进行热修复,好处就是补丁包小而且可以立即生效,但是对平台的兼容性较差,且只能给予方法进行修补。

nuwa方案采用java层替换类的方式来,的兼容性比andfix要好很多,其主要是提前加载插件的类,并将其放在basedexclassloader类端pathlist中的dexelements数组的前面。

微信的方案是下载一个差量的dex包,在客户dexelements后台进行patch生成一个完整的包,然后整体将此完整的dex文件直接替换到数组中,微信的方案是在nuwa方案上的一种完善,微信方案下载的补丁包更小,nuwa和微信的方案都需要重启应用。

andfix和nuwa热修复方案都是只适用于代码修复的,并不包含资源更新,微信tinker号称已经支持资源的加载。

目前市面上还有一种360的免安装方案,就是droidplugin,这个方案是既可以加载实体应用的dex也可以加载其资源。droidplugin是动态代理了activitymanager、packagemanager等系统服务在应用中的远程对象,来启动四大组件,使用动态加载dex和资源的方式来加载实体app。

综上,使用类似droidplugin的思路来处理热修复的问题,同时又没有动态代理系统各种服务,主要使用动态加载的方式来进行免安装升级,成为目前的研究目标。



技术实现要素:

为解决上述技术问题,本发明提供了一种android系统无感知应用安装升级的方法,无需动态代理android系统的各种服务,使用动态加载的方式来进行免安装升级。

一种android系统无感知应用安装升级的方法,其中,具体包括如下步骤:

1)、打包创建宿主应用:

1-1)、给宿主应用定义;

1-2)、引用安卓系统的application类;

引用安卓系统的content.componentcallbacks类;

引用安卓系统的content.context类;

引用安卓系统的content.pm.applicationinfo类;

引用安卓系统的content.pm.packagemanager类;

引用安卓系统的content.res.assetmanager类;

引用安卓系统的content.res.resources类;

引用安卓系统的text.textutils类;

1-3)、引用宿主应用自定义的uusafe.shell.common.zclassloader类;

引用宿主应用自定义的uusafe.shell.common.zglobal类;

引用宿主应用自定义的uusafe.shell.common.zloader类;

1-4)、引用java语言的ref.weakreference类;

引用java语言的reflect.field类;

引用java语言的reflect.method类;

引用java提供的collection类;

引用java提供的hashmap类;

引用java提供的lis类;

引用java提供的map类;

1-5)、用自定义的zapplication类去代替安卓应用默认的application类;

新定义mfieldassets类,并进行初始化;

新定义objectmat类,并进行初始化;

用自定义类的attachbasecontext()方法替换安卓应用默认的application类中的attachbasecontext()方法,具体如下:

自定义类加载器zloader类,new创建一个zloader的实例mloader,mloader检查是否有实体应用安装包real.apk,再使用zclassloader.patch方法将mloader添加到宿主应用的类加载器的父亲位置(parent);再根据实体应用的真实的application类名,调用java中反射的newinstance()方法获取实体应用的application实例mimpl,再用java的反射方法拿到宿主应用的android.app.activitythread类的实例mat,接着使用java的反射方法去替换mat中所有的application的对象实例,最后调用mimpl的attach函数从而来触发实体应用自己的application(mimpl)的attachbasecontext()方法,来真正的开始执行实体应用相关的操作;

宿主应用的入口是application类,在宿主应用工程中创建一个继承系统application的类zapplication,用于在宿主应用刚启动时增加一个处理事件的时机,在宿主应用工程的清单文件(androidmanifest.xml)中把所有的实体应用中的清单文件都拷贝过来,把实体应用的安装包real.apk放到宿主应用工程的assets文件夹中,安卓提供aapt命令打包编译资源文件生成r.java和resources.arsc,通过javac编译java文件生成class文件,通过dx来将java生成的class文件转化为安卓使用的dex文件,再使用aapt命令将之前生成的各种文件打包生成安卓安装包apk文件,同时安卓工程中的assets文件夹下面的文件原封不动的被aapt打入安装包,aapt最终生成包含实体应用的宿主安装包shell.apk,然后编译宿主应用工程打包生成宿主应用(shell.apk),将实体应用(real.apk)打入宿主应用安装包中,宿主应用运行时通过安卓系统提供的assetmanager.open(real.apk)方法来操作assets目录下的实体应用安装包文件;

2)、安装宿主应用,宿主应用安装包包括清单文件(androidmanifest)、assets文件夹、可执行文件(classes.dex)、资源文件(res),assets文件夹包括实体应用安装包,安装过程具体如下:安卓系统将安装包复制到/data/app/目录下,解压缩apk文件使用packagemanager来解析安装包的清单文件(androidmanifest.xml)文件,获取应用注册的各种组件信息并缓存,然后执行dex优化过程将优化后的dex文件放入/data/dalvik_cache/文件夹下面,应用运行的时候直接执行此目录下优化好的dex文件;

2a)、宿主应用的清单文件androidmanifest.xml包含实体应用real.apk所有的清单文件,宿主应用的清单文件包括:实体应用清单文件声明的组件:活动activity、广播broadcastreceiver、服务service、内容提供器contentprovider和用于向安卓系统声明的该实体应用所需要的权限;

宿主应用安装完成后,为了安全以及应用间隔离,安卓系统创建一个应用自己的私有目录“/data/data/om.suzhu.shell/”来存储运行时生成的文件和文件夹,如数据库文件,sharedprefence文件(android应用保存配置的文件)等,进入步骤2b);

2b)、宿主应用启动时,安卓系统调用宿主应用的zapplication类即初始化类的attachbasecontext()方法,安卓应用启动时候会触发调用attachbasecontext()方法,判断实体应用real.apk是否已经被放到/data/data/om.suzhu.shell/.uu/目录下:如果没有则调用安卓方法assetmanager.open(real.apk),将asset文件夹下面的实体应用real.apk放到宿主应用的运行目录/data/data/com.suzhu.shell(宿主应用包名)/.uu/中,用于宿主应用对其加载启动,之后,进入步骤3);如果实体应用real.apk已经被放到/data/data/om.suzhu.shell/.uu/目录下,则直接进入步骤3;

3)、检测升级:

进行联网,检测是否有新版本实体应用,若有新版本实体应用,进行联网更新,并将新版本实体应用的安装包下载到之前保存实体应用安装包的宿主应用的asset文件夹中,然后进入步骤3),如果没有新的实体应用安装包则直接进行步骤4);

4)、实体应用dex字节码文件(可执行文件)优化:

dex字节码文件(可执行文件)优化是个耗时过程,在宿主应用的清单文件中指定一个服务zservice继承于系统的service,用于处理可执行文件的优化工作,为宿主应用正常执行,在宿主清单文件中为zservice服务指定一个单独的进程,此进程里的zservice服务里创建了一个自己的类加载器zclassloader,继承于系统的classloader,然后初始化zclassloader,利用classloader初始化时优化传入路径apk文件的机制来实现实体应用dex字节码文件的优化,得到安卓设备能直接操作的机器码,优化完成后生成优化后的odex文件,即optimize-dex文件,等宿主应用下一次启动的时候类加载器如果发现odex文件存在,则直接使用已经优化好的新版本实体应用的可执行文件;

5)、实体应用启动:

5a)、加载实体应用的类:

安卓中类是通过类加载器classloader加载的,创建classloader的时候需要传入应用的dex文件路径、相应库路径,类加载器通过所述路径进行相关文件的处理,包括如在相关路径下加载类、优化dex路径下的dex文件,新创建一个类加载器zclassloader,并将类加载器zclassloader的参数dex文件路径、库路径相应赋值为实体应用的dex文件路径,如此在使用类加载器加载要使用的各种类的时候就会自动的去相关路径下寻找,具体执行过程是:

判断宿主应用是否被启动,若否,继续等待,若是,宿主应用执行初始化方法attachbasecontext(),在宿主的attachbasecontext()方法中进行实体应用类加载器(classloader)的处理,详细过程如下:

首先调用安卓系统提供的类的getclassloader()方法得到宿主应用的类加载器orgclassloader,再调用系统类加载器(classloader)提供的getparent()方法(orgclassloader.getparent())得到原始类加载器orgclassloader的父加载器parentclassloader,创建在宿主的attachbasecontext()方法被系统触发调用的时候初始化自己的类加载器zclassloader用于加载实体应用中使用到的各个类,zclassloader继承于系统的classloader类,构造函数:privatezclassloader(classloaderorgparentclassloader,stringdexsearchpath,stringlibsearchpath,filecachedir),传入参数包括宿主应用类加载器(orgclassloader)的父类加载器(orgparentclassloader)做为自己类加载器的父类加载器,传入实体应用安装包路径作为字节码文件的加载位置(dexsearchpath),传入使用到的库的路径(libsearchpath),最后一个参数是dex进行优化后存放的路径(cachedir);根据类加载器的双亲委派机制,系统优先使用父一级的类加载器的原理,通过java反射调用的方式修改orgclassloader的父类加载器为zclassloader,拿到原始类加载器的父亲,再调用field.set(orgclassloader,zclassloader),将zclassloader设置为原始类加载器的父亲,保证类加载器zclassloader优先orgclassloader使用,来达到加载实体应用类字节码的目的;

5b)、应用配置信息替换:替换内存中已经生成的应用的全局的各种信息,包括应用全局配置里面的初始化类(application)的实例、应用程序信息缓存(minitialapplication)、所有应用进程信息缓存(mallapplications)以及应用资源信息缓存(loadedapk)对象、资源对应的loadedapk里面的application;宿主应用启动后安卓系统在内存中生成多种缓存数据,用于应用运行时使用,如果使用实体应用的各种应用信息则需要将这些内存中的数据都替换为实体应用的相应数据:通过前述生成的zclassloader调用实体应用的可执行文件中的实现类,使用java的反射调用方式根据实体应用的application类的名字创建实体应用的初始化类,即application类;然后再利用java的反射机制(reflect机制)替换宿主应用的全局配置(即activitythread)中的所有的初始化类(application)的实例为实体应用的初始化类(application)的实例,所述替换是使用反射的方法直接修改相应对象实例里面的对应的域(field)的值,替换的内容包括:应用程序信息缓存(minitialapplication)、所有应用进程信息缓存(mallapplications)以及应用资源信息缓存(loadedapk)对象和资源对应的loadedapk里面的application,一一替换,直到全部替换完;

5c)、应用资源信息替换,宿主应用启动的时候安卓系统会将其安装包中的资源信息通过其原始的资源加载器(assetmanager)进行加载,每次运行的时候系统都会根据应用安装包的位置生成资源加载器assetmanager,并且通过loadedapk,即资源与代码中引用的对应对象,将资源跟代码中引用的对应关系保存起来,loadedapk对象是安卓安装包文件(apk)在内存中的表示,安卓系统在内存中创建loadedapk的实例,并将资源信息和代码引用信息都保存在其中,之后,通过contextimpl(即应用上下文环境)对象将应用资源信息保存起来,系统把生成的资源加载器对象保存到contextimpl实例对象中的mresources对象中,通过各个activity、contentprovider、service对象将此组件要使用的相关资源信息保存;生成新的资源加载器,通过java的反射方式将新的资源加载器替换到相关的loadedapk、contextimpl中,并生成应用各个组件需要的应用资源信息缓存,组件包括activity、provider、service,当应用真正执行相关activity活动、service服务、contentprovider内容提供者的初始化的时候进行对应的替换;

详细的实现过程如下:在宿主应用的初始化方法即attachbasecontext被系统调用的时候,使用系统方法构造生成新的资源加载器即newassetmanager()实例,通过assetmanager中的添加方法即addassetpath生成新的资源加载器实例,然后将此新的资源加载器替换到相应的应用运行时的环境中,首先是替换应用全局配置activitythread类实例中的mactiveresources对象中的各个resources子对象对应的资源加载器,mactiveresources对象是包含resources对象的集合,然后再替换activitythread实例中所有的loadedapk对象中的mresources对象中的资源加载器massets,在activitythread中loadedapk对象主要被系统保存在一个集合即mpackages对象中,通过java的反射机制取得这个集合即mpackages对象,然后再使用java的反射机制一一替换其中的资源加载器为实体应用的资源加载器,下一步替换应用上下文环境即context实例中的mresources对象中的资源加载器(massets),宿主应用的application对象也是实体应用要利用的上下文环境实例,application类是继承于context类,application实例就是应用的上下文实例,java的反射机制反射宿主的application对象拿到其中的mresources对象,再反射替换掉其中的资源加载器massets,最后再缓存应用的各个组件中使用的资源信息,即resourceinfo、主题资源和文字资源等信息,即遍历实体应用的“活动”信息即activityinfo中各个“活动”即activity的资源信息,遍历各个服务的信息即serviceinfo中的资源信息及各个内容提供者信息即providerinfo中的资源信息并保存在缓存中,当相应组件被使用的时候将此实体应用的资源信息提供给相应组件,各组件均是在activitythread类的消息队列中进行执行的,均通过mh的handler对象进行,根据安卓handler对象优先执行其中的mcallback的特性,通过java的反射机制替换此mcallback,然后当各组件初始化消息过来的时候根据之前保存的内存中的缓存来替换组件使用的resourceinfo、主题资源和文字资源;

5d)按照安卓系统正常启动应用的处理来执行此实体应用的启动过程:在点击图标启动正常应用的时候安卓桌面应用会先向系统的系统活动管理服务即activitymanagerservice简称ams发送启动请求,ams收到后会fork出一个新的进程作为此应用的进程,此新进程启动后创建消息事件处理队列,然后开始向ams进行注册,以便应用跟ams可以相互通信;经过前面的类加载器、资源等替换后,开始完善执行实体应用的application的注册方法,向系统活动管理服务即activitymanagerservice注册,这个注册过程对应在activitythread类中的handlebindapplication()方法,是实体应用能否正常启动的关键一步,实现这个过程以便实体应用能正常启动,handlebindapplication()方法主要包含两个操作:实现安卓系统中application类中的attach()方法执行的各个操作、执行相关的“内容提供器”的安装即installcontentproviders()方法;通过类加载器生成实体应用的application的实例,然后反射调用其attach()方法来完成attach()方法的处理,同样通过反射来调用activitythread中的installcontentproviders方法来实现实体应用的installcontentproviders方法,至此即完成整个应用的初始化即attachbasecontext()的处理,之后进入步骤6);

6)、执行宿主的oncreate()方法,执行application实例的oncreate()方法;通过java的反射机制对应调用执行实体的应用初始化类即application)的oncreate()方法;

7)、至此整个替换过程完成,可以至此使用动态加载的实体应用。

本发明实现了整个apk包的完整静默升级,包含dex文件以及资源文件,可以在用户无感知的情况下通过替换类加载器、替换资源加载器和资源管理器来加载新实体应用安装包中的的指令、数据和其相对应的资源文件,从而实现使用新版本应用的目的。

附图说明

图1为本发明android系统无感知应用安装升级的方法的流程示意图;

图2为宿主应用安装包结构框架示意图。

具体实施方式

本发明提供了一种android系统无感知应用安装升级的方法,如图1所示的流程示意图,具体包括如下步骤:

1)、打包创建宿主应用:

1-1)、给宿主应用定义;

1-2)、引用安卓系统的application类;

引用安卓系统的content.componentcallbacks类;

引用安卓系统的content.context类;

引用安卓系统的content.pm.applicationinfo类;

引用安卓系统的content.pm.packagemanager类;

引用安卓系统的content.res.assetmanager类;

引用安卓系统的content.res.resources类;

引用安卓系统的text.textutils类;

1-3)、引用宿主应用自定义的uusafe.shell.common.zclassloader类;

引用宿主应用自定义的uusafe.shell.common.zglobal类;

引用宿主应用自定义的uusafe.shell.common.zloader类;

1-4)、引用java语言的ref.weakreference类;

引用java语言的reflect.field类;

引用java语言的reflect.method类;

引用java提供的collection类;

引用java提供的hashmap类;

引用java提供的lis类;

引用java提供的map类;

1-5)、用自定义的zapplication类去代替安卓应用默认的application类;

新定义mfieldassets类,并进行初始化;

新定义objectmat类,并进行初始化;

用自定义的attachbasecontext类去替换安卓应用默认的attachbasecontex类,具体如下:

自定义类加载器zloadermloader,mloader检查是否有实体应用安装包real.apk,再使用zclassloader.patch方法将mloader添加到宿主应用的类加载器的父亲位置(parent);再根据实体应用的真实的application类名,调用java中反射的newinstance()方法获取实体应用的application实例mimpl,再用java的反射方法拿到宿主应用的android.app.activitythread类的实例mat,我们再使用java的反射方法去替换mat中所有的application的对象实例,最后调用mimpl的attach函数从而来触发实体应用自己的application(mimpl)的attachbasecontext()方法,来真正的开始执行实体应用相关的操作;

宿主应用的入口都是application类,在宿主应用工程中创建一个继承系统application的类zapplication,用于在宿主应用刚启动时增加一个处理事件的时机,在宿主应用工程的清单文件(androidmanifest.xml)中把所有的实体应用中的清单文件都拷贝过来,把实体应用的安装包real.apk放到宿主应用工程的assets文件夹中,安卓提供aapt命令打包编译资源文件生成r.java和resources.arsc,通过javac编译java文件生成class文件,通过dx来将java生成的class文件转化为安卓使用的dex文件,再使用aapt命令将之前生成的各种文件打包生成安卓安装包apk文件,而安卓工程中的assets文件夹下面的文件是会原封不动的被aapt打入安装包,aapt最终生成包含实体应用的宿主安装包shell.apk,然后编译宿主应用工程打包生成宿主应用(shell.apk),将实体应用(real.apk)打入宿主应用安装包中,宿主应用运行时通过安卓系统提供的assetmanager.open(real.apk)方法来操作assets目录下的实体应用安装包文件;图2为宿主应用安装包结构框架示意图;

2)、安装宿主应用,宿主应用安装包包括清单文件(androidmanifest)、assets文件夹、可执行文件(classes.dex)、资源文件(res),assets文件夹包括实体应用安装包,安装过程具体如下:安卓系统将安装包复制到/data/app/目录下,解压缩apk文件使用packagemanager来解析安装包的清单文件(androidmanifest.xml)文件,获取应用注册的各种组件信息并缓存,然后会执行dex优化过程将优化后的dex文件放入/data/dalvik_cache/文件夹下面,应用运行的时候直接执行此目录下优化好的dex文件;

2a)、宿主应用的清单文件androidmanifest.xml包含实体应用real.apk所有的清单文件,宿主应用的清单文件包括:实体应用清单文件声明的组件:活动activity、广播broadcastreceiver、服务service、内容提供器contentprovider和用于向安卓系统声明的该实体应用所需要的权限;

宿主应用安装完成后,为了安全以及应用间隔离,安卓系统创建一个应用自己的私有目录“/data/data/om.suzhu.shell/”来用于存储运行时生成的文件和文件夹,如数据库文件,sharedprefence文件(保存配置的文件)等,进入步骤2b);

2b)、宿主应用启动时,安卓系统调用宿主应用的zapplication类(即初始化类)的attachbasecontext()方法,安卓应用启动时候会触发调用attachbasecontext方法,此时,判断是否实体应用real.apk已经被放到/data/data/om.suzhu.shell/.uu/目录下,如果没有则要调用安卓方法assetmanager.open(real.apk),来将asset文件夹下面的实体应用real.apk放到宿主应用的运行目录(/data/data/com.suzhu.shell(宿主应用包名)/.uu/)中,用于宿主应用对其加载启动;之后,进入步骤3);

3)、检测升级:

进行联网,检测是否有新版本实体应用,若有新版本实体应用,进行联网更新,并将新版本实体应用的安装包下载到之前保存实体应用安装包的宿主应用的asset文件夹中,然后进入步骤3),如果没有新的实体应用安装包则直接进行步骤4);

4)、实体应用dex字节码文件(可执行文件)优化:

dex字节码文件(可执行文件)优化是个耗时过程,在宿主应用的清单文件中指定一个服务zservice继承于系统的service,用于处理可执行文件的优化工作,为宿主应用正常执行,在宿主清单文件中为zservice服务指定一个单独的进程,此进程里的zservice服务里创建了一个自己的类加载器zclassloader,继承于系统的classloader,然后初始化zclassloader,利用classloader初始化时会优化了传入路径apk文件的机制来实现实体应用dex字节码文件的优化,得到安卓设备能直接操作的机器码,优化完成后生成优化后的odex文件(即,optimize-dex文件)等应用下一次启动的时候类加载器如果发现odex文件存在,则就可以直接使用已经优化好的新版本实体应用的可执行文件;

5)、实体应用启动:

5a)、加载实体应用的类:

安卓中类都是通过类加载器classloader加载的,让实体应用的dex文件路径、各种库路径都能被类加载器找到,新创建一个类加载器zclassloader,并将其dex文件路径、库路径都为其相应赋值为实体应用的dex文件路径,这样,在使用类加载器加载要使用的各种类的时候就会自动的去相关路径下寻找,具体执行过程是:

判断宿主应用是否被启动,若否,继续等待,若是,宿主应用执行初始化方法attachbasecontext(),在宿主的attachbasecontext()方法中进行实体应用类加载器(classloader)的处理,详细过程如下:

首先调用安卓系统提供的类的getclassloader()方法得到宿主应用的类加载器orgclassloader,再调用系统类加载器(classloader)提供的getparent()方法(orgclassloader.getparent())得到(所述的得到就是调用前述的函数得到其返回值)原始类加载器orgclassloader的父加载器parentclassloader,本设计创建了在宿主的attachbasecontext()方法被系统触发调用的时候初始化自己的类加载器zclassloader用于加载实体应用中使用到的各个类,zclassloader是继承于系统的classloader类的,构造函数:privatezclassloader(classloaderorgparentclassloader,stringdexsearchpath,stringlibsearchpath,filecachedir),传入参数包括宿主应用类加载器(orgclassloader)的父类加载器(orgparentclassloader)做为自己类加载器的父类加载器,传入实体应用安装包路径作为字节码文件的加载位置(dexsearchpath),传入使用到的库的路径(libsearchpath),最后一个参数是dex进行优化后存放的路径(cachedir);根据类加载器的双亲委派机制,系统会优先使用父一级的类加载器的原理,通过java反射调用的方式修改orgclassloader的父类加载器为zclassloader,拿到原始类加载器的父亲,再调用field.set(orgclassloader,zclassloader),来将zclassloader设置为原始类加载器的父亲,这样来保证类加载器zclassloader优先orgclassloader使用,来达到加载实体应用类字节码的目的;

5b)、应用配置信息替换:主要是替换内存中已经生成的应用的全局的各种信息(主要包括应用全局配置里面的初始化类(application)的实例、应用程序信息缓存(minitialapplication)、所有应用进程信息缓存(mallapplications)以及应用资源信息缓存(loadedapk)对象、资源对应的loadedapk里面的application等,详见后文),宿主应用启动后安卓系统就会在内存中生成多种缓存数据,用于应用运行时使用,如果想使用实体应用的各种应用信息则需要将这些内存中的数据都替换为实体应用的:通过前文生成的zclassloader本设计可以调用实体应用的可执行文件中的实现类,本设计提供java的反射调用方式根据实体应用的application类的名字创建实体应用的初始化类(即application类);然后再利用java的反射机制(reflect机制)替换宿主应用的全局配置(即activitythread)中的所有的初始化类(application)的实例为实体应用的初始化类(application)的实例(“替换”的具体设置和执行过程请给出说明:替换就是使用反射的方法直接修改某个对象实例里面的某个域(field)的值),这个要替换的比较多,主要有应用程序信息缓存(minitialapplication)、所有应用进程信息缓存(mallapplications)以及应用资源信息缓存(loadedapk)对象和资源对应的loadedapk里面的application,一一替换,直到全部替换完;

5c)、应用资源信息替换,宿主应用启动的时候安卓系统会将其安装包中的资源信息通过其原始的资源加载器(assetmanager)进行加载(每次运行的时候系统都会根据应用安装包的位置生成资源加载器assetmanager),并且通过loadedapk(资源与代码中引用的对应)对象将资源跟代码中引用的对应关系保存起来(简单的说loadedapk对象是安卓安装包文件(apk)在内存中的表示,安卓系统会在内存中创建loadedapk的实例,并将资源信息和代码引用信息都保存在其中),通过contextimpl(即应用上下文环境)对象将应用资源信息保存起来(系统会把生成的资源加载器对象保存到contextimpl实例对象中的mresources对象中),通过各个activity、contentprovider、service对象将此组件要使用的相关资源信息保存;所以本设计要做的就是生成新的资源加载器,通过java的反射方式将之替换到相关的loadedapk、contextimpl中,并生成应用各个组件(组件包括activity、provider、service)需要的应用资源信息缓存,当应用真正执行相关activity(即活动)、service(即服务)、contentprovider(即内容提供者)”的初始化的时候进行对应的替换;

详细的实现过程如下:在宿主应用的初始化方法(即attachbasecontext)被系统调用的时候使用系统方法构造生成新的资源加载器(即newassetmanager()实例),通过assetmanager中的添加方法(即addassetpath)生成新的资源加载器实例,然后本设计要将此新的资源加载器替换到相应的应用运行时环境中,首先是替换应用全局配置(activitythread类实例)中的mactiveresources对象(此对象是个包含了resources对象的集合)中的各个resources子对象对应的资源加载器,然后再替换activitythread实例中所有的loadedapk对象中的mresources对象中的资源加载器(massets),在activitythread中loadedapk对象主要被系统保存在一个集合mpackages对象中,本设计中则是通过java的反射机制来拿到这个集合,然后一个个的再使用java的反射机制替换其中的资源加载器为实体应用的资源加载器,下一步替换应用上下文环境即(context实例)中的mresources对象中的资源加载器(massets),这个很简单,宿主应用的application对象也是实体应用要利用的上下文环境实例(application类是继承context类的,application实例就是应用的上下文实例),本设计中通过java的反射机制反射宿主的application对象拿到其中的mresources对象,再反射替换掉其中的资源加载器(massets),最后再缓存应用的各个组件中使用的资源信息,即resourceinfo、主题资源和文字资源等信息,即遍历实体应用的“活动”信息(即activityinfo)中各个“活动”(即activity)的资源信息,遍历各个服务的信息(即serviceinfo)中的资源信息及各个内容提供者信息(即providerinfo)中的资源信息并将之保存在缓存中,当各个组件要被使用的时候将此实体应用的资源信息提供给各个组件,各个组件都是在activitythread类的消息队列中进行执行的,这些处理都是通过其中的叫mh的handler对象进行的,根据安卓handler对象会优先执行其中的mcallback的特性,通过java的反射机制替换此mcallback,然后当各个组件初始化消息过来的时候根据之前保存的内存中的缓存来替换组件使用的resourceinfo、主题资源和文字资源等信息;

5d)按照安卓系统正常启动应用的处理来执行此实体应用的启动过程:在点击图标启动正常应用的时候安卓桌面应用会先向系统的系统活动管理服务(即activitymanagerservice,简称ams)发送启动请求,ams收到后会fork出一个新的进程作为此应用的进程,此进程启动后会创建消息事件处理队列,然后开始向ams进行注册,以便应用跟ams可以相互通信;经过前面的类加载器、资源等替换后,就需要开始完善执行实体应用的application的注册方法,向系统活动管理服务(activitymanagerservice)注册,这个注册过程就是对应在activitythread类中的handlebindapplication()方法,这是实体应用能否正常启动的关键一步,要来实现这个过程以便实体应用能正常启动,handlebindapplication()方法主要包含两个操作:实现安卓系统中application类中的attach()方法执行的各个操作)、执行相关的“内容提供器”的安装(即installcontentproviders())方法;通过类加载器生成实体应用的application的实例,然后反射调用其attach()方法来完成attach()方法的处理,同样也是通过反射来调用activitythread中的installcontentproviders方法来实现实体应用的installcontentproviders方法,这一步完成后本设计就完成整个应用的初始化(即attachbasecontext())的处理,然后进入下一步;

6)、完成应用初始化后,最后一步是执行宿主的oncreate()方法,安卓应用启动的时候一般都是要执行application实例的oncreate()方法的,所以本设计也需要完成这一步;具体实现也是通过java的反射机制来对应调用执行实体的应用初始化类(即application)的oncreate()方法;

7)、至此整个替换过程完成,可以至此使用动态加载的实体应用。

本发明技术方案的特征点如下:

1、替换类加载器的方式:本技术方案使用的方法是在应用的bootclassloader和dex加载器之间增加一级类加载器,所增加的类加载器用于加载实体的dex,根据类加载双亲委派机制会优先使用新增加的类加载器,之后才可以支持加载实体应用。

2、加载实体包资源的方式:

目前修改类加载器保证我们可以正常加载实体应用的dex,但是资源还需要加载进来。我们在应用的初始化方法(即attachbasecontext)被系统调用的时候生成新的资源加载器,通过其中的添加方法(即addassetpath)方法将实体应用文件的路径加入此资源加载器中,然后在获取单例的资源管理器实例,修改其中的应用活动资源(即mactiveresources)中对应的资源加载器,然后再修改应用全局配置(即activitythread)中所有的loadedapk中具体的资源对应的资源加载器(即assetmanager),然后再替换应用上下文环境(即contextimpl)中的数据段(即mresources)中的资源加载器(即assetmanager)。最后再遍历并缓存实体应用的各个组件的资源信息(即各个activity、contentprovider、service中使用的相关资源信息),然后在实体应用的各个组件具体使用的时候(即安卓系统真正进行执行启动activity、创建service、创建contentprovider的时候)进行相应替换,从而完成资源的替换。

本发明跟andfix方法、nuwa方法相比可以加载完整的新实体包以包含其中的资源;使用了增加父classloader的机制来加载dex,反射替换assetmanager的方法替换资源,虽然有一些机型适配的问题,但是在实际使用过程中应用的稳定性还是很可靠的。

跟微信tinker相比,本方案下载的升级包更大,会更耗流量,但是本方案没有微信的那个升级包原包的patch过程,不会出现合并过程中的占用apu、内存过高等会导致的不稳定的问题;而且本方案支持加载升级包中的资源;

本方案相对360droidplugin方案,大大减少代码复杂度、应用稳定性等问题,更为精简地利用动态加载的方式实现免安装升级。

以上所述,仅为本发明的具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本发明揭露的技术范围内,可轻易想到变化或替换,都应涵盖在本发明的保护范围之内。因此,本发明的保护范围应所述以权利要求的保护范围为准。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1