PackageManagerService Android 8.1 源码解读 01

2023-05-16

一、PackageManagerService 是什么? 

答: PackageManagerService(简称 【PKMS】),是 Android 系统中核心服务之一,负责应用程序的安装,卸载,信息查询,解析等工作。与apk相关的信息都在这个服务里可以查询到。

 

二、PKMS 概述信息:

  1. Android系统启动时,由【system-server进程】来启动(应用程序的管理服务器PKMS),这个服务类负责【扫描】系统中【特定的目录】,【寻找】目录中的【APK格式的文件】,再对这些文件进行【解析】,最后得到对应的应用程序相关信息,完成应用程序的【安装】。
     
  2. PKMS在【安装应用】过程中, 会【全面解析】应用程序的【AndroidManifest.xml 文件】, 获取四大组件相关的信息,如:Activity,Service, BroadcastReceiver,ContextProvider 等,然后结合PKMS服务,就可以在OS中正常的使用应用程序了。
  3. 在Android系统中, 系统启动时由【SystemServer】类启动PKMS服务, 启动该服务后会【执行】应用程序的【安装过程】。
     
  4. 接下来后就会重点的介绍 (SystemServer启动PKMS服务的过程, 讲解在Android系统中安装应用程序的过程)


a、简单来需知:PKMS 与 AMS 一样,也是Android系统核心服务之一,非常非常的重要,主要完成以下核心功能:

  • 1、【解析】AndroidNanifest.xml清单文件,解析清单文件中的【所有节点信息】;
  • 2、【扫描】.apk文件,安装系统应用,安装本地应用等
  • 3、【管理】本地应用,主要有, 安装,卸载,应用信息查询 等

说白了,就是解析apk,扫描apk,管理apk,三部曲进行的;


b、分析的核心源码路径地址如下:

/frameworks/base/core/java/android/app/ApplicationPackageManager.java
/frameworks/base/services/java/com/android/server/SystemServer.java
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
/frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java
/frameworks/base/services/core/java/com/android/server/pm/Installer.java
/frameworks/base/services/core/java/com/android/server/pm/Settings.java
/frameworks/base/services/core/java/com/android/server/pm/permission/BasePermission.java
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
/frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
/frameworks/base/core/java/android/content/pm/IPackageManager.aidl
/frameworks/base/core/java/android/content/pm/PackageManager.java
/frameworks/base/core/java/com/android/server/SystemConfig.java


三、一部曲 - PKMS角色位置:

a、代码的结构如下:

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
......
}

public abstract class PackageManager { 
......
}

public class ApplicationPackageManager extends PackageManager {
......
}


public interface IPackageManager extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
		public static abstract class Stub extends android.os.Binder 
                         implements android.content.pm.IPackageManager {
				private static final java.lang.String DESCRIPTOR = "android.content.pm.IPackageManager";
				/** Construct the stub at attach it to the interface. */
				public Stub() {
						this.attachInterface(this, DESCRIPTOR);
				}
				......
		}
		
		private static class Proxy implements android.content.pm.IPackageManager {
				private android.os.IBinder mRemote;
				Proxy(android.os.IBinder remote) {
						mRemote = remote;
				}
				@Override public android.os.IBinder asBinder() {
						return mRemote;
				}
				......
		}
		......
}

 

b、客户端可通过【Context.getPackageManager()】获得【ApplicationPackageManager】对象, 而【mPM】指向的是【Proxy代理】,当调用到mPM.方法后,将会调用到IPackageManager的Proxy代理方法,然后通过Binder机制中的【mRemote】与服务端【PackageManagerService】通信 并调用到PackageManagerService的方法;

public class ContextWrapper extends Context {
    Context mBase;
    public PackageManager getPackageManager() {
        return mBase.getPackageManager();
    }
}

public class ContextImpl extends Context {
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }
        //通过ActivityThread类获取的;
        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;
    }
}

// 应用程序的入口类
public final class ActivityThread {
    //静态可见的接口类
    static volatile IPackageManager sPackageManager;
    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }
}

public class ApplicationPackageManager extends PackageManager {
    private final IPackageManager mPM;//真正的接口
    protected ApplicationPackageManager(ContextImpl context,
                              IPackageManager pm) {
        mContext = context;
        mPM = pm;
    }
}

c、自我总结:PKMS是属于Binder机制的服务端角色,客户端通过Context对象获取接口类对象
 

四、二步曲 - PKMS 启动过程分析:

a、PKMS的过程图如下:

b、PKMS启动过程描述:
b.1、SystemServer启动PKMS: 先是在【SystemServer.startBootstrapServices()】函数中启动PKMS服务,
b.2、再调用【startOtherServices()】函数中对dex优化,磁盘管理功能,让PKMS进入【systemReady】状态。

c、SystemServer调用PKMS的七步流程:

c.0、SystemServer.java中的run函数,通过调用SystemServer.startBootstrapServices()函数中启动PKMS服务,在调用startOtherServices()函数;

c.1、第一步:startBootstrapServices()首先启动Installer服务,也就是【安装器】,随后判断当前的设备是否处于加密状态,如果是则只是【解析核心应用】,接着调用PackageManagerService的静态方法main来【创建pkms对象

// 第一步:启动Installer
// 阻塞等待installd完成启动,以便有机会创建具有适当权限的关键目录,如/data/user。
// 我们需要在初始化其他服务之前完成此任务。
traceBeginAndSlog("StartInstaller");
Installer installer = mSystemServiceManager.startService(Installer.class);
traceEnd();

c.2、第二部:通过系统属性【"vold.decrypt"】,获取是否有加密设备,同时判断是否仅仅处理核心服务

// 第二步:获取设别是否加密(手机设置密码),如果设备加密了,则只解析"core"应用,mOnlyCore
= true,后面会频繁使用该变量进行条件判断
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
    Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
    mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
    Slog.w(TAG, "Device encrypted - only parsing core apps");
    mOnlyCore = true;
}

c.3、第三部:调用PKMS.main方法,实例化PKMS

/
/ 第三步:调用main方法初始化PackageManagerService
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
// PKMS是否是第一次启动
mFirstBoot = mPackageManagerService.isFirstBoot();
// 定义一个引用;
mPackageManager = mSystemContext.getPackageManager();
traceEnd();

PKMS.main方法:

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.自检查初始化设置的属性
    PackageManagerServiceCompilerMapping.checkProperties();
    // 新建PKMS的对象,
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    m.enableSystemUserPackages();
    ServiceManager.addService("package", m);//将服务添加到SM中
    final PackageManagerNative pmn = m.new PackageManagerNative();
    ServiceManager.addService("package_native", pmn);//将服务添加到SM中
    return m;
}

c.4、第四步:如果设备没有加密,操作它,管理A/B OTA dexopting,主要依据mOnlyCore来做判断,为false表没有加密

// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
// 第四步:如果设备没有加密,操作它。管理A/B OTA dexopting。
if (!mOnlyCore) {
    boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
            false);
    if (!disableOtaDexopt) {
        traceBeginAndSlog("StartOtaDexOptService");
        try {//激活OTA服务
            OtaDexoptService.main(mSystemContext, mPackageManagerService);
        } catch (Throwable e) {
            reportWtf("starting OtaDexOptService", e);
        } finally {
            traceEnd();
        }
    }
}

c.5、第五步:如果设备没有加密,执行【updatePackagesIfNeeded】函数,调用PKMS的【performDexOptUpgrade】完成dex优化;

if (!mOnlyCore) {
    traceBeginAndSlog("UpdatePackagesIfNeeded");
    try {//啥事情都没有干,只是转掉
        // 第五步:如果设备没有加密,执行performDexOptUpgrade,完成dex优化;
        mPackageManagerService.updatePackagesIfNeeded();
    } catch (Throwable e) {
        reportWtf("update packages", e);
    }
    traceEnd();
}

c.6、第六步:执行【performFstrimIfNeeded】函数,这里有一个显示UI,是否需要显示:"正在优化存储空间。"

traceBeginAndSlog("PerformFstrimIfNeeded");
try {
    // 第六步:最终执行performFstrim,完成磁盘维护
    mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
    reportWtf("performing fstrim", e);
}
traceEnd();

c.7、第七步:执行【systemReady()】,说明PKMS已经准备就绪,这里就是做最后的工作

traceBeginAndSlog("MakePackageManagerServiceReady");
try {
    // 第七步:PKMS准备就绪
    mPackageManagerService.systemReady();
} catch (Throwable e) {
    reportWtf("making Package Manager Service ready", e);
}
traceEnd();

c.8、分析PKSM,重点需要从第三部开始,下一篇继续分析;

PackageManagerService Android 8.1 源码解读 02
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PackageManagerService Android 8.1 源码解读 01 的相关文章

随机推荐

  • 求正整数n所有可能的和式的组合

    求正整数n所有可能的和式的组合 xff08 如 xff1b 4 61 1 43 1 43 1 43 1 1 43 1 43 2 1 43 3 2 43 1 43 1 2 43 2 xff09 首先说一下 xff0c 群里面很多人在问这个东东
  • Error:FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:t

    今日份遇到的 bug xff1a Error 注 某些输入文件使用或覆盖了已过时的 API 注 有关详细信息 请使用 Xlint deprecation 重新编译 注 某些输入文件使用了未经检查或不安全的操作 注 有关详细信息 请使用 Xl
  • JVM调优-解决native heap持续增长

    问题的提出 xff0c 分析 xff0c 请参考JNI 小心 xff0c 内存怪兽出没 xff08 简单的说起来 xff0c 就是java进程占用了4G内存 xff0c 但是折腾来折腾去 xff0c 整个JVM的堆才100M上下 xff0c
  • Centos 7 安装openjdk8 /jdk8/jre8 mvn-3.5.2 其他版本雷同

    文章目录 openjdk8jdk8 jre8maven 3 5 2源码下载指导 openjdk8 一 使用yum命令搜索支持jdk版本 yum search java grep jdk 二 使用yum安装jdk8 yum install y
  • 【2023最新版】Hexo+github搭建个人博客并绑定个人域名

    Hexo 43 github搭建个人博客并绑定个人域名 本篇教程完整讲述了如何利用Hexo 43 github搭建个人博客并且绑定自己的域名 xff0c 成为自己的网站 xff01 我的博客网站 xff1a 武师叔 做一个有趣而不甘平庸的人
  • H13-531云计算HCIE V2.0——1~400常错题和知识点总结

    1 100 35 FusionStorage Block无法是被配置RAID的磁盘 一定要将RAID信息删除后 Fusionstrage block才能识别到这些磁盘 错误 61 Ceilometer监控通过在计算节点部署Compute服务
  • 我的2013

    今天是2013年的最后一天 xff0c 天气格外的晴朗 xff0c 站在公司的写字楼上 xff0c 能够看到远处的山水 一直都习惯在一年的最后总结一下 xff0c 总结自己哪些地方在成长 xff0c 哪些地方有收获 xff0c 哪些地方需要
  • 项目管理中的TR点

    TR的意思是技术评审 xff0c 是英语Technical Review的简写 一般项目管理中有以下一些技术评审点需要关注 xff1a TR1 概念阶段技术评审点 xff1a 产品需求和概念技术评审 xff08 业务需求评审 xff09 T
  • linux ln 命令使用参数详解(ln -s 软链接)

    这是linux中一个非常重要命令 xff0c 请大家一定要熟悉 它的功能是为某一个文件在另外一个位置建立一个同不的链接 xff0c 这个命令最常用的参数是 s 具体用法是 xff1a ln s 源文件 目标文件 当 我们需要在不同的目录 x
  • 别再让C++头文件中出现“using namespace xxx;”

    在这里 xff0c 我毫不回避地说了这句话 xff1a 引用 我再也不想在任何头文件中看到 using namespace xxx 了 作为一个开发者 团队领导者 xff0c 我经常会去招聘新的项目成员 xff0c 有时候也帮助其他组的人来
  • Linux 查看监听端口的方法

    61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • SVN MERGE 和冲突

    摘要 xff1a 最佳做法是避免冲突 冲突时 xff0c 不要把branch merge到trunk 先由最新版本的trunk得到branch 然后再修改文件 xff0c 直接merge过去就行 这样不会有冲突 先用svn merge dr
  • Linux命令之basename使用

    basename 命令 首先使用 help 参数查看一下 basename命令参数很少 xff0c 很容易掌握 basename help 用法示例 xff1a basename usr bin sort 输出 34 sort 34
  • android log详解

    之前两篇文章之后 xff0c 打算再分享一点儿经验 xff1a 之前文章见这里 xff1a 1 xff0c 全看懂了 加两年经验 语音朗读 语音识别 语音控制软件源码 2 xff0c 学生作品 配置NDK集成开发环境全过程第一版 这次打算通
  • 各种编码知识简介

    本文主要介绍我们在日常开发中接触到了latin1 xff0c GBK xff0c GB18030 xff0c UTF 8 编码几种 下面首先来看看这几种编码的的区别 latin1 1 先来看看latin1 参考百度百科 Latin1 是IS
  • Linux 技巧:让进程在后台可靠运行的几种方法

    我们经常会碰到这样的问题 xff0c 用 telnet ssh 登录了远程的 Linux 服务器 xff0c 运行了一些耗时较长的任务 xff0c 结果却由于网络的不稳定导致任务中途失败 如何让命令提交后不受本地关闭终端窗口 网络断开连接的
  • nohup命令浅析

    要将一个命令放到后台执行 xff0c 我们一般使用nohup sh command amp amp 都知道是放到后台执行这个命令 xff0c 那么nohup是做什么的 xff1f 这就要从unix的信号说起 xff0c unix的信号机制可
  • 《曾国藩家书大全集》读书笔记——励志篇

    曾国藩将立志作为人生第一要义 xff0c 只要能立志 xff0c 便人人都可以做圣贤豪杰 人生不但要立志 xff0c 还要持之以恒 xff0c 持之以恒是人生第一美德 xff0c 人而无恒 xff0c 将一事无成 曾国藩很重视逆境对人心志的
  • 书,永远的朋友

    我自己认为我是一个不大喜欢看书的人 xff0c 相对于书 xff0c 我可能跟喜欢看视频和同高手一起讨论交流 但是 xff0c 真正静下心来 xff0c 想着这么多年来 xff0c 对我影响很大的一些书 xff0c 也能想到一些 索性 xf
  • PackageManagerService Android 8.1 源码解读 01

    一 PackageManagerService 是什么 xff1f 答 PackageManagerService xff08 简称 PKMS xff09 xff0c 是 Android 系统中核心服务之一 xff0c 负责应用程序的安装