PMS解析l⽂件的过程
⼀、前⾔经典词句
前段时间在看当下主流的安卓插件化技术原理的时候,发现⽬前插件化技术对于四⼤组件的处理基本都是通过代理来实现的(动态注册的⼴播接收器除外)。简单说就是需要先在主包⾥预埋⼀个注册在l中的组件,再由这个组件来连接SystemServer和插件中的业务逻辑。
这⾥难免就会有⼀些疑问,系统从l⽂件解析出来的四⼤组件的信息存放在哪⾥?能否不利⽤预埋+代理的技术,直接通过修改中间的存储容器来实现四⼤组件的插件化?
要想解答这些疑惑,我们就得知道系统是如何从l中解析出四⼤组件的?以及解析后的组件信息⼜是如何保存的?
系统中负责解析l⽂件的系统服务是PackageManagerService(以下简称PMS)。PMS中关于l⽂件的处理逻辑⼊⼝主要有两处,⼀个是SystemServer进程启动时,另⼀个则是应⽤安装/更新时。两个⼊⼝对于xml的解析流程⼤体上是⼀致的,本篇⽂章只分析SystemServer进程启动时,PMS对l的解析流程。
⼆、相关知识
2.1 ⽅法后缀LI、LIF、LPr、LPw的含义
三、调⽤流程
SystemServer的启动属于开机流程中的⼀步,⼊⼝如下:
SystemServer.main()
/**
* The main entry point from zygote.
* zygote进程会调⽤该⽅法
*/
public static void main(String[] args){
new SystemServer().run();
}
main()⽅法中new了⼀个SystemServer对象,并调⽤了它的run()⽅法
SystemServer.run()
private void run(){
try{
一年级试卷分析// 省略部分代码,只列出关键部分的代码
// The system rver should never make non-oneway calls
画羊简笔画Binder.tWarnOnBlocking(true);
// Initialize native rvices.
System.loadLibrary("android_rvers");
// Create the system rvice manager.
// SystemServiceManager是整个Service的⼤管家
mSystemServiceManager =new SystemServiceManager(mSystemContext);
mSystemServiceManager.tStartInfo(mRuntimeRestart,
mRuntimeStartElapdTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
}finally{
}
// Start rvices.
try{
// start critical rvices, include PMS/AMS
startBootstrapServices(t);
// start esntial rvices
startCoreServices(t);
// start other rvice
startOtherServices(t);
}catch(Throwable ex){
Slog.e("System","******************************************");
Slog.e("System","************ Failure starting system rvices", ex);
throw ex;
}finally{
}
}
run()⽅法中主要做了⼀些系统启动时的初始化⼯作,其中很关键的⼀步就是启动各项rvice服务。PMS就是在startBootstrapServices()中初始化的。
SystemServer.startBootstrapServices(@NonNull TimingsTraceAndSlog t)
/**
本金怎么算* Starts the small tangle of critical rvices that are needed to get the system off the
* ground. The rvices have complex mutual dependencies which is why we initialize them all
* in one place here. Unless your rvice is also entwined in the dependencies, it should be
* initialized in one of the other functions.
*/
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t){
// 省略部分代码
try{
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
}finally{
}
// Now that the package manager has started, register the dex load reporter to capture any
// dex files loaded by system rver.
/
/ The dex files will be optimized by the BackgroundDexOptService.
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = PackageManager();
// 省略部分代码
}
startBootstrapServices()⽅法中调⽤了PMS的main()⽅法来初始化PMS服务
PackageManagerService.main()
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest,boolean onlyCore){
// 省略部分代码
/
/ new⼀个Java层的PMS对象
PackageManagerService m =new PackageManagerService(injector, onlyCore, factoryTest);
// 省略部分代码
// 将new出来的PMS对象注册到ServiceManager中,之后我们便能够通过Context对象的getPackageManager()来获取PM对象了,这部分源码在 tPackageManager()/PackageManager()中
m.installWhitelistedSystemPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
这⾥我们主要关注PMS的实例化过程,PMS的构造函数如下:
PackageManagerService.PackageManagerService()
/** Directory where installed applications are stored */
private static final File sAppInstallDir =
new DataDirectory(),"app");
public PackageManagerService(Injector injector,boolean onlyCore,boolean factoryTest){ // 省略部分代码
if(!mOnlyCore){
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir,0, scanFlags | SCAN_REQUIRE_KNOWN,0,
packageParr, executorService);
}
蘑菇汤的家常做法
// 省略部分代码
}
PMS的构造函数中通过scanDirTracedLI()来扫描已安装的三⽅App apk信息,路径为/data/app/ PackageManagerService.scanDirTracedLI()
private void scanDirTracedLI(File scanDir,final int parFlags,int scanFlags,
long currentTime, PackageParr2 packageParr, ExecutorService executorService){
try{
scanDirLI(scanDir, parFlags, scanFlags, currentTime, packageParr, executorService);
}finally{
}
}
PackageManagerService.scanDirLI()
private void scanDirLI(File scanDir,int parFlags,int scanFlags,long currentTime,
PackageParr2 packageParr, ExecutorService executorService){
ParallelPackageParr parallelPackageParr =
new ParallelPackageParr(packageParr, executorService);
// Submit files for parsing in parallel
int fileCount =0;
世界和平for(File file : files){
final boolean isPackage =(isApkFile(file)|| file.isDirectory())
&&!PackageInstallerService.Name());
if(!isPackage){
// Ignore entries which are not packages
continue;
}
// 继续往下调⽤了parallelPackageParr.submit()
parallelPackageParr.submit(file, parFlags);
fileCount++;
}
}
ParallelPackageParr.submit(File scanFile, int parFlags)
/
**
经典智力题
* Submits the file for parsing
* @param scanFile file to scan
* @param parFlags par flags
*/
public void submit(File scanFile,int parFlags){
mExecutorService.submit(()->{
ParResult pr =new ParResult();
try{
pr.scanFile = scanFile;
/
/ 继续往下调⽤了parrPackage()
pr.pardPackage =parPackage(scanFile, parFlags);
}catch(Throwable e){
pr.throwable = e;
}finally{
}
try{
mQueue.put(pr);
}catch(InterruptedException e){
Thread.currentThread().interrupt();
/
/ Propagate result to callers of take().
// This is helpful to prevent main thread from getting stuck waiting on
// ParallelPackageParr to finish in ca of interruption
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
ParallelPackageParr.parPackage(File scanFile, int parFlags)
protected PardPackage parPackage(File scanFile,int parFlags)
throws PackageParr.PackageParrException {
return mPackageParr.parPackage(scanFile, parFlags,true);
}
PackageParr2.parPackage(File packageFile, int flags, boolean uCaches)
/**
* TODO(b/135203078): Document new package parsing
*/
@AnyThread
public PardPackage parPackage(File packageFile,int flags,boolean uCaches) throws PackageParrException {
// 有缓存的话优先使⽤缓存
if(uCaches && mCacher !=null){
PardPackage pard = CachedResult(packageFile, flags);
if(pard !=null){
return pard;
}
}
long parTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis():0;
ParInput input = ().ret();
// 继续往下调⽤了parPackage()
ParResult<ParsingPackage> result = parsingUtils.parPackage(input, packageFile, flags);最好的个性签名
// 省略部分代码
return pard;
}
ParsingPackageUtils.parPackage(ParInput input, File packageFile, int flags)