Framework - PMS

一、概念

frameworks/base/services/core/java/com.android.server.pm.PackageManagerService.java

PackageManageService, 简称PMS,用来管理所有包信息(安装、卸载、更新、解析AndroidManifest)。AndroidManefest中注册了 APP 所有的四大组件和权限等信息,PMS提前将 AMS 要用的信息解析保存在内存中提供快速调用。

二、启动PMS过程 

Zygote 启动 SystemServer.main() 调用 run() 调用 startBootstrapServices()  启动 PMS,并添加到 ServiceManager 中用于进程间 Binder 通信。

public final class SystemServer {
    public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run() {
        startBootstrapServices();
    }
    private void startBootstrapServices() {
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
    }
}
public class PackageManagerService extends IPackageManager.Stub implements PackageSender {
    public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
        PackageManagerServiceCompilerMapping.checkProperties();
        //创建自己的实例
        PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);
        m.enableSystemUserPackages();
        //将PMS注册到ServiceManager(AMS找PMS拿数据时就通过ServiceManager找到PMS)
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    }
}

三、获取PMS过程

例如在 Activity 中调用 getPackageManager() 时:

//ContextWrapper.java
public PackageManager getPackageManager() {
    return mBase.getPackageManager();    //mBase 是 ContextImpl
}
//ContextImpl.java
public PackageManager getPackageManager() {
    if (mPackageManager != null) {
        return mPackageManager;
    }
    IPackageManager pm = ActivityThread.getPackageManager();
    if (pm != null) {
        // Doesn't matter if we make more than one instance.
        return (mPackageManager = new ApplicationPackageManager(this, pm));
    }
    return null;
}
//ActivityThread.java
public static IPackageManager getPackageManager() {
    if (sPackageManager != null) {
        return sPackageManager;
    }
    IBinder b = ServiceManager.getService("package"); //通过 ServiceManager 拿到 PMS
    sPackageManager = IPackageManager.Stub.asInterface(b); //Binder 通信
    return sPackageManager;
}

四、解析AndroidManifest过程

至少消耗70%的开机时间。

  • 扫描系统(/data/app/)和用户(/system/app/)已安装应用目录下的所有 apk 文件并解压。
  • 获取 AndroidManifest.xml 文件并进行 dom 解析,将权限、四大组件、Application等信息转换为 Java Bean 保存在内存中供 AMS 查询。

4.1 扫描

scanDirLI() 使用 for 循环遍历已安装软件目录(系统system/app、第三方data/app),如果是 apk 文件就调用 parallelPackageParser.submit() 提交任务给子线程的包解析器处理(Android 10.0起使用子线程加快开机速度,之前版本是直接解析)。

public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
	// 扫描 /system/app 目录下的 apk 文件
    scanDirTracedLI(systemAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM, 0);	
	// 扫描用户目录下的apk文件
	scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
}

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
    for (File file : files) {
        // 判断是否是 .apk 后缀的文件
        final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            continue;    // Ignore entries which are not packages
        }
        // 提交给子线程包解析器处理apk文件
        parallelPackageParser.submit(file, parseFlags);
    }
}

4.2 解析

根据传过来的 apk 路径判断是文件还是目录,文件走 parseMonolithicPackage() 调用 parseBaseApk() 解析 apk 文件,通过 dom 解析 AndroidManefest 将节点信息存放到对应的 JavaBean 中然后再存放到 Package 对象的集合中,最后放在 PMS 成员变量 ArrayMap<String, PackageParser.Package> mPackage 中(即缓存在内存中,key是包名)方便后续 AMS 查询。(Android 9.0起解析结果会开启缓存,没有缓存就解析每个 app 的 AndroidManefest)。

ParallelPackageParser.java

public void submit(File scanFile, int parseFlags) {
    pr.scanFile = scanFile;    //传入待解析的apk文件
    pr.pkg = parsePackage(pp, scanFile, parseFlags);    //交给packageParser解析
}

 PackageParser.java

public Package parsePackage(File packageFile, int flags, boolean useCaches) throws PackageParserException {
     //如果有缓存直接返回
     Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
     if (parsed != null) {
         return parsed;
     }        
	 //apk文件不是目录,所以会走的parseMonolithicPackage()
     if (packageFile.isDirectory()) {
         parsed = parseClusterPackage(packageFile, flags);
     } else {
         parsed = parseMonolithicPackage(packageFile, flags);
     }
}

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
    //解析apk文件
    final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
}

private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException {
    //解压apk文件
    final int cookie = assets.findCookieForPath(apkPath);
	//dom解析AndroidManifest.xml
    parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
    final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
}

private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException {
     //后续的流程就是将xml解析的权限、四大组件等信息存到同名的JavaBean字段中再存到Package对象集合中
     //所有解析出来的Package对象最后会放在PMS成员变量 mPackage 中,是一个ArrayMap,key是包名。
     final Package pkg = new Package(pkgName);
     return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}

public final static class Package implements Parcelable {
	//包名
	public String packageName;
	//一个APP中所有的权限
    public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
    public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
    //一个APP中所有的四大组件
    public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
    public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
    public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
    public final ArrayList<Service> services = new ArrayList<Service>(0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值