android开发浅谈之packagemanagerservice(pkms)(代码片段)

hfreeman2008 hfreeman2008     2023-02-02     702

关键词:

本文基于Android10.0

主要从以下几个方面着手:

PKMS启动
PKMS安装APK
PKMS卸载APK

PKMS启动

这里我简单的将其分为以下几个步骤:

  • 1.SystemServer通过PKMS的main方法启动PKMS
  • 2.PKMS构造方法中初始化Settings
  • 3.扫描各个系统目录下APP相关信息

1.SystemServer通过PKMS的main方法启动PKMS

PKMS启动是在SystemServer.startBootstrapServices:

mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

PackageManagerService.main方法:

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) 
	.....
	//构造方法
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    m.enableSystemUserPackages();
    ServiceManager.addService("package", m);
    final PackageManagerNative pmn = m.new PackageManagerNative();
    ServiceManager.addService("package_native", pmn);
    return m;

2.PKMS构造方法中初始化Settings

PackageManagerService.PackageManagerService

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) 
    ......
    //Settings的初始化
    mSettings = new Settings(Environment.getDataDirectory(),
                    mPermissionManager.getPermissionSettings(), mPackages);    

mSettings是全局的,它主要协助PMS保存系统中安装APP包名,权限,四大组件等相关信息的存储,Settings会在/data/system目录下创建相关的文件来保存这些APP相关的信息

frameworks\\base\\services\\core\\java\\com\\android\\server\\pm\\Settings.java

查看Settings.Settings方法:

Settings(File dataDir, PermissionSettings permission,
        Object lock) 
	......
    mSystemDir = new File(dataDir, "system");
    mSystemDir.mkdirs();
    FileUtils.setPermissions(mSystemDir.toString(),
            FileUtils.S_IRWXU|FileUtils.S_IRWXG
            |FileUtils.S_IROTH|FileUtils.S_IXOTH,
            -1, -1);
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    mPackageListFilename = new File(mSystemDir, "packages.list");
    FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

    final File kernelDir = new File("/config/sdcardfs");
    mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

    // Deprecated: Needed for migration
    mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
    mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");

我们大概看一下/data/system生成的文件信息:
packages.xml----主要是包括包的权限信息:

<package name="com.sohu.inputmethod.sogou.oem" codePath="/system/priv-app/SogouInput" nativeLibraryPath="/system/priv-app/SogouInput/lib" primaryCpuAbi="armeabi" publicFlags="945307205" privateFlags="8" ft="179aac28790" it="179aac28790" ut="179aac28790" version="1312" userId="10076" isOrphaned="true">
    <sigs count="1" schemeVersion="1">
        <cert index="0" key="30820248308201b102045a3eccafc07082c70bb30ef4" />
    </sigs>
    <perms>
        <item name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" granted="true" flags="0" />
        <item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
......
        <item name="com.android.launcher.permission.INSTALL_SHORTCUT" granted="true" flags="0" />
        <item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
    </perms>
    <proper-signing-keyset identifier="8" />
</package>

packages-backup.xml

packages.list------------------应用列表

com.android.soundrecorder 10135 0 /data/user/0/com.android.soundrecorder platform:targetSdkVersion=29 1023,3003 0 63

packages-stopped.xml
packages-stopped-backup.xml

3.扫描各个系统目录下APP相关信息

PackageManagerService.PackageManagerService:

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) 
    ......
    // Collect vendor/product/product_services overlay packages. (Do this before scanning
    // any apps.)
    // For security and version matching reason, only consider overlay packages if they
    // reside in the right directory.
    scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
            mDefParseFlags
            | PackageParser.PARSE_IS_SYSTEM_DIR,
            scanFlags
            | SCAN_AS_SYSTEM
            | SCAN_AS_VENDOR,
            0);
    scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
            mDefParseFlags
            | PackageParser.PARSE_IS_SYSTEM_DIR,
            scanFlags
            | SCAN_AS_SYSTEM
            | SCAN_AS_PRODUCT,
            0);
      ......
       scanDirTracedLI(productServicesAppDir,
         mDefParseFlags
         | PackageParser.PARSE_IS_SYSTEM_DIR,
         scanFlags
         | SCAN_AS_SYSTEM
         | SCAN_AS_PRODUCT_SERVICES,
         0);

从Android 10,0的代码来看,扫描路径的顺序为:

/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app

PKMS安装APK

adb install命令 安装apk

我们使用adb install 命令来安装apk:

先来看PackageManagerService的消息定义:

static final int SEND_PENDING_BROADCAST = 1;
static final int INIT_COPY = 5;  //此是在安装apk前,copy apk的消息
static final int POST_INSTALL = 9;  //安装前的消息
static final int WRITE_SETTINGS = 13;
static final int WRITE_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
static final int CHECK_PENDING_VERIFICATION = 16;
static final int START_INTENT_FILTER_VERIFICATIONS = 17;  //intent filter 的校验消息
static final int INTENT_FILTER_VERIFIED = 18;
static final int WRITE_PACKAGE_LIST = 19;
static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
static final int ENABLE_ROLLBACK_STATUS = 21;
static final int ENABLE_ROLLBACK_TIMEOUT = 22;
static final int DEFERRED_NO_KILL_POST_DELETE = 23;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
static final int NEED_UPDATAE_APPLICATION = 25;
static final int NEED_UPDATAE_ACTIVITYINFO = 26;

我们先确认系统是如何发送消息MSG_COMMIT:

我们在PackageInstallerSession.commit添加日志信息:

public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) 
......
    Slog.v(TAG, "commit " , new Throwable());
    mHandler.obtainMessage(MSG_COMMIT).sendToTarget();

这个是日志信息输出:

com.android.server.pm.PackageInstallerSession.commit(PackageInstallerSession.java:920)
android.content.pm.PackageInstaller$Session.commit(PackageInstaller.java:1079)
com.android.server.pm.PackageManagerShellCommand.doCommitSession(PackageManagerShellCommand.java:2851)
com.android.server.pm.PackageManagerShellCommand.runInstall(PackageManagerShellCommand.java:1082)
com.android.server.pm.PackageManagerShellCommand.onCommand(PackageManagerShellCommand.java:169)
android.os.ShellCommand.exec(ShellCommand.java:104)
com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:22266)
android.os.Binder.shellCommand(Binder.java:881)
android.os.Binder.onTransact(Binder.java:765)
android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:4923)
com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:4141)
android.os.Binder.execTransactInternal(Binder.java:1021)
android.os.Binder.execTransact(Binder.java:994)

查看PackageManagerShellCommand.onCommand:

public int onCommand(String cmd) 
......
    switch(cmd) 
        case "path":
            return runPath();
        case "dump":
            return runDump();
        case "list":
            return runList();
        case "resolve-activity":
            return runResolveActivity();
        case "query-activities":
            return runQueryIntentActivities();
        case "query-services":
            return runQueryIntentServices();
        case "query-receivers":
            return runQueryIntentReceivers();
        case "install":
            return runInstall();//安装apk
  ......                      

可以看出adb shell pm command命令的入口就是在这个方法中添加,而我们执行adb install命令,后面就会来到此处的runInstall方法。

最后,就会来到PackageInstallerSession.commit:

public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) 
......
    mHandler.obtainMessage(MSG_COMMIT).sendToTarget();//发送MSG_COMMIT消息

然后,我们在PackageManagerService$PackageHandler.doHandleMessage就可以接受到消息MSG_COMMIT:

void doHandleMessage(Message msg) 
......
    switch (msg.what) 
        case INIT_COPY: 
            HandlerParams params = (HandlerParams) msg.obj;
            if (params != null) 
                if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                        System.identityHashCode(params));
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                params.startCopy();//执行copy操作
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            
            break;
        

查看日志,我们就知道,会将此apk复现/data/app/vmdl2019169999.tmp:

PackageManager: init_copy: InstallParams78e22b5 file=/data/app/vmdl2019169999.tmp
PackageManager: startCopy UserHandle0: InstallParams78e22b5 file=/data/app/vmdl2019169999.tmp

PackageManagerService$HandlerParams.startCopy

final void startCopy() 
    if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
    handleStartCopy();
    handleReturnCode();

再查看日志:

PackageManager: Renaming /data/app/vmdl2019169999.tmp to /data/app/flipboard.cn-MArVEpS9MmEGIfVhBcSfbg==

我们发现有一个对复制过来的文件进行重命名的操作

再查看日志:

PackageManager: installNewPackageLI: Package2dbf84 flipboard.cn

在PackageManagerService.preparePackageLI添加日志信息:

private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
        throws PrepareFailure 
    ........
    // Remember this for later, in case we need to rollback this install
    String pkgName1 = pkg.packageName;
    Slog.v(TAG, "preparePackageLI installNewPackageLI" , new Throwable());
    if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);

可以看到日志信息:

com.android.server.pm.PackageManagerService.preparePackageLI(PackageManagerService.java:18268)
com.android.server.pm.PackageManagerService.installPackagesLI(PackageManagerService.java:17328)
com.android.server.pm.PackageManagerService.installPackagesTracedLI(PackageManagerService.java:16675)
com.android.server.pm.PackageManagerService.lambda$processInstallRequestsAsync$13$PackageManagerService(PackageManagerService.java:14919)

再查看,发现日志信息:

PackageManager:   Activities: flipboard.activities.LaunchActivity flipboard.activities.BriefingLaunchFlipboardAlias flipboard.activities.LaunchActivityAlias 
PackageManager:   Receivers: flipboard.receivers.FirstLaunchReminderReceiver flipboard.notifications.NotificationExpirationReceiver 
PackageManager:   Registered content provider: flipboard.remoteservice.feeds.china, className = flipboard.remoteservice.FLFeedItemContentProvider, isSyncable = false

也就是需要添加要安装的应用中四大组件activity,receiver,content provider,services信息:

我们在ComponentResolver.addProvidersLocked添加打印日志信息:

private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) 
    Slog.v(TAG, "addProvidersLocked" , new Throwable());

其打印日志为:

com.android.server.pm.ComponentResolver.addProvidersLocked(ComponentResolver.java:557)
com.android.server.pm.ComponentResolver.addAllComponents(ComponentResolver.java:375)
com.android.server.pm.PackageManagerService.commitPackageSettings(PackageManagerService.java:12483)
com.android.server.pm.PackageManagerService.commitReconciledScanResultLocked(PackageManagerService.java:11366)
com.android.server.pm.PackageManagerService.commitPackagesLocked(PackageManagerService.java:17263)
com.android.server.pm.PackageManagerService.installPackagesLI(PackageManagerService.java:17400)
com.android.server.pm.PackageManagerService.installPackagesTracedLI(PackageManagerService.java:16675)
com.android.server.pm.PackageManagerService.lambda$processInstallRequestsAsync$13$PackageManagerService(PackageManagerService.java:14919)

查看ComponentResolver.addAllComponents:

void addAllComponents(PackageParser.Package pkg, boolean chatty) 
    final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>();
    synchronized (mLock) 
        addActivitiesLocked(pkg, newIntents, chatty);//添加activity
        addReceiversLocked(pkg, chatty); //添加Receiver
        addProvidersLocked(pkg, chatty);  //添加Provider
        addServicesLocked(pkg, chatty);  //添加Service
    

其ComponentResolver类中定义四大组件的信息为:

/** All available activities, for your resolving pleasure. */
@GuardedBy("mLock")
private final ActivityIntentResolver mActivities = new ActivityIntentResolver();

/** All available providers, for your resolving pleasure. */
@GuardedBy("mLock")
private final ProviderIntentResolver mProviders = new ProviderIntentResolver();

/** All available receivers, for your resolving pleasure. */
@GuardedBy("mLock")
private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();

/** All available services, for your resolving pleasure. */
@GuardedBy("mLock")
private final ServiceIntentResolver mServices 查看详情  

android开发浅谈之写在前面的话

...相关的职业选择了2011年8月----2013年8月深圳康佳通信科技androidapp开发刚入行,有点怕怕。带我的领导是一位北大的美女,智商碾压绝大部分人&# 查看详情

android开发浅谈之inputmethodmanagerservice(代码片段)

...应用–InputMethodService我们先讨论输入法应用部分:以android内置的输入法LatinIME为例,先看LatinIME输入的AndroidManifest.xml对其定义:<serviceandroid:name="LatinIME"android:label="@st 查看详情

android开发浅谈之写在前面的话

...相关的职业选择了2011年8月----2013年8月深圳康佳通信科技androidapp开发刚入行,有点怕怕。带我的领导是一位北大的美女,智商碾压绝大部分人,公司要求比较高,比较严,技术开发特别规范。本以后这会是我... 查看详情

浅谈之merge-sort-join

初接触执行计划,做练习时执行sql(如图一)图一:查看其执行计划(如图二)图二:看到上面这个执行计划用到mergesortjoin(排序合并联合查询),刚开始没有理解为什么这条执行计划里还有sortjoin,emp表里deptno字段不是已经有... 查看详情

qt浅谈之二:钟表(时分秒针),qsplitter实现自由伸缩滑动窗口good

http://blog.csdn.net/taiyang1987912/article/details/30272105http://blog.csdn.net/taiyang1987912/article/details/50717179http://blog.csdn.net/taiyang1987912/article/category/2314763 查看详情

qt浅谈之二十一log调试日志

一、简单介绍     近期因调试code时,想了解程序的流程,但苦于没有一个简易的日志记录,不停使用qDebug打印输出,而终于提交代码时得去多次删除信息打印,有时还会出现新改动的代码分不清是哪些部分。... 查看详情

设计模式浅谈之----设计模式简介

  1.何为设计模式设计模式是一个通过定义、使用和测试去解决特定问题的方法,并且由于设计模式是在面向对象之后为人所知的,基本思想与面向对象不可分割。在软件工程中,设计模式是一般只在给定条件下会重复性... 查看详情

qt浅谈之四十二钟表摆动显示百分比

一、简介       Qt下利用定时器实现指针指示百分比的钟摆的动态显示效果,可以适用于显示百分比或进度条的进度或时间的刻度值(在圆形进度条上的一种改进)。效果如下:二、详解1、代码(1)Dashb... 查看详情

llvm每日谈之五十五浅谈对pass的错误认知及其原因

Pass作为LLVM的一个重要的组成部分,在LLVMIR层面和LLVMBackend层面都发挥了重要的作用。很多LLVM的使用者容易将Pass理解为LLVMIR层面的analysis和transform,而忽略了Pass在LLVMBackend层面的作用。而实际上,Pass在LLVMBackend层面发... 查看详情

python实例浅谈之五python守护进程和脚本单例运行(代码片段)

一、简介守护进程最重要的特性是后台运行;它必须与其运行前的环境隔离开来,这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等;它可以在系统启动时从启动脚本/etc/rc.d... 查看详情

如何使用 packageManager 在 android java 中获取克隆的应用程序?

】如何使用packageManager在androidjava中获取克隆的应用程序?【英文标题】:HowcanIgettheclonedappsinandroidjavausingpackageManager?【发布时间】:2019-09-1919:13:43【问题描述】:我正在开发一个新的android启动器应用程序,并且我成功地能够使... 查看详情

浅谈混合开发与android,js数据交互

本文是作者原创,如转载请注明出处!一.概论现在时代已经走过了移动互联网的超级火爆阶段,市场上移动开发人员已经趋于饱和,显然,只会原生APP的开发已不能满足市场的需求,随着H5的兴起与火爆,H5在原生APP中的使用越来越广泛,... 查看详情

android开发应用版本升级怎么实现

...应用的版本号。  要怎么获取PackageInfo对象呢?可以通过PackageManager对象来获取。PackageManager是一个检索当前已安装在设备上的相关应用程序包的各种信息的类。PackageManager对象中的getPackageInfo方法可以获取PackageInfo对象,该方法... 查看详情

PackageManager#installPackage 不适用于 Android N

】PackageManager#installPackage不适用于AndroidN【英文标题】:PackageManager#installPackagedoesn\'tworkforAndroidN【发布时间】:2016-11-1408:52:14【问题描述】:当使用版本24的构建工具和带有N映像(npd56n)的Android设备时,我无法使用PackageManager#install... 查看详情

llvm每日谈之五十七tablegen(代码片段)

...m-tblgen。通常在build目录下的bin目录里。TableGen主要是帮助开发者开发和维护特定领域的信息记录,方便开发者更好的构建这些信息记录,避免错误。尤其是在面对大量的信息记录的时候,用起来比较方便。TableGen 查看详情

浅谈android,以及android程序的helloworld

前言我本是做服务器开发,有时候工作需要和基于Android、Windows等系统进行协同开发,为了知己知彼,我花了一段时间研究了一下Android。至此,站在一个后台开发者的角度,总结一下Android,以及Android和后... 查看详情

Android:PackageManager.getSystemAvailableFeatures() 在 Nexus9 上没有按预期工作

】Android:PackageManager.getSystemAvailableFeatures()在Nexus9上没有按预期工作【英文标题】:Android:PackageManager.getSystemAvailableFeatures()isnotworkingasexpectedonNexus9【发布时间】:2015-03-2021:48:21【问题描述】:我正在尝试使用PackageManager.getSystemAv 查看详情