Android PackageManager Service详解(5.1源码)(四)

2.4 APP执行代码

APP运行时可执行的代码,主要有三部分:

1)  虚拟机初始化时加载的系统jar包,主要包含framework.jar和libcore.jar,分别对应android framework代码和jdk代码

2)  APP自身程序代码,也就是打包入APK的dex文件

3)  APP程序运行需要额外加载的library,对应manifest里配置的uses-library字段

前两个没啥好讲的,重点讲下第三部分,app可以在manifest里头声明自身运行需要额外的library,但是,这里仅仅只是声明,最终还是要看系统有没有配置这个sharelibrary,配置的方式可查看2.2 初始化SystemConfig,如果app的uses-library在系统中不存在,apk会安装失败。

PMS初始化share library代码:

   ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();

            for (int i=0; i<libConfig.size(); i++) {

                mSharedLibraries.put(libConfig.keyAt(i),

                        new SharedLibraryEntry(libConfig.valueAt(i), null));

     }

通过library path来初始化SharedLibraryEntry并保存到mSharedLibraries中。

在apk数据解析时,会调用updateSharedLibrariesLPw来将apk配置的user library更新到对应的package对象:

    private void updateSharedLibrariesLPw(PackageParser.Package pkg,

            PackageParser.Package changingLib) throws PackageManagerException {

        if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {

            final ArraySet<String> usesLibraryFiles = new ArraySet<>();

            int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;

            for (int i=0; i<N; i++) {

                final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i));

                if (file == null) {

                    throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,

                            "Package " + pkg.packageName + " requires unavailable shared library "

                            + pkg.usesLibraries.get(i) + "; failing!");

                }

                addSharedLibraryLPw(usesLibraryFiles, file, changingLib);

            }

            N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;

            for (int i=0; i<N; i++) {

                final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));

                if (file == null) {

                    Slog.w(TAG, "Package " + pkg.packageName

                            + " desires unavailable shared library "

                            + pkg.usesOptionalLibraries.get(i) + "; ignoring!");

                } else {

                    addSharedLibraryLPw(usesLibraryFiles, file, changingLib);

                }

            }

            N = usesLibraryFiles.size();

            if (N > 0) {

                pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]);

            } else {

                pkg.usesLibraryFiles = null;

            }

        }

    }

遍历usesLibraries和usesOptionalLibraries,调用addSharedLibraryLPw依次将share library添加到usesLibraryFiles,并最终保存到pkg.usesLibraryFiles。

private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,

            PackageParser.Package changingLib) {

        if (file.path != null) {

            usesLibraryFiles.add(file.path);

            return;

        }

        PackageParser.Package p = mPackages.get(file.apk);

        if (changingLib != null && changingLib.packageName.equals(file.apk)) {

            // If we are doing this while in the middle of updating a library apk,

            // then we need to make sure to use that new apk for determining the

            // dependencies here.  (We haven't yet finished committing the new apk

            // to the package manager state.)

            if (p == null || p.packageName.equals(changingLib.packageName)) {

                p = changingLib;

            }

        }

        if (p != null) {

            usesLibraryFiles.addAll(p.getAllCodePaths());

        }

    }

file.path不为空,直接添加到usesLibraryFiles即可

程序启动的时候,AcivityThread会通过app对应的application info来创建LoadedApk,然后LoadedApk内部根据dex和usesLibraryFiles来创建app对应的classloader。

2.5 APK文件扫描

APK扫描的过程,其实就是数据收集的过程,扫描的一些代码,其实在上头的内容中就有提到, PMS中调用scanPackageLI扫描一个apk文件,为了让整个思路更加清晰,接下去将基于首次扫描一个nonsystem apk来分析,至于其他的一些细节,这里就不做更多的描述,大家可自行阅读源码。

先介绍几个核心类:

                   

从下到上,依次包含,详细介绍如下

1:PackageParser.Package 对应一个apk包完整的原始数据

2:PackageSetting 包含PackageParser.Package对象实例,说明它也对应一个apk包的数据,不同的是,它还包含apk相关配置数据,比如,apk内部哪些component是被disable等。

3:Settings 包含PackageSetting对象列表,也就是说它包含了系统所有apk数据

还有就是PackageParser,顾名思义,负责APK数据解析。

扫描新apk的流程描述:

1)  调用scanPackageLI,传入要解析的apk文件

2)  创建PackageParser对象,接着调用parsePackage来解析apk清单数据,返回
PackageParser.Package对象pkg,pkg包含了apk原始的清单数据

3)  接着调用collectCertificatesLI获取apk的签名数据并保存到pkg中,这个函数的详细介绍可看1.2.4 PMS中签名相关代码介绍

4)  调用scanPackageLI并传入pkg,接着调用scanPackageDirtyLI

5)  接着判断pkg.mSharedUserId是否为空,如果不为空,说明apk设置了share user id,那就要调用getSharedUserLPw创建新的share user id

6)  接着调用mSettings.getPackageLPw生成pkg对应的PackageSetting对象pkgSetting

7)  针对非系统app(parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR)== 0),调用updateSharedLibrariesLPw更新pkg的usesLibraryFiles

8)  如果是新安装app((scanFlags &SCAN_NEW_INSTALL) != 0), 则查看app内部声明的provider是否已经被其他已安装的app定义,如果是,抛出异常

9)  调用fixProcessName生成app对应的进程名

10)调用createDataDirsLI在/data/data/下创建app私有目录

11)调用NativeLibraryHelper.copyNativeBinariesForSupportedAbi拷贝so文件,接着调用setNativeLibraryPaths更新pkg.applicationinfo中的nativeLibraryDir等信息

12)调用performDexOptLI对apk中的dex做优化

13)调用mSettings.insertPackageSettingLPw(pkgSetting, pkg);将app对应的PackageSetting添加到Settings中

14)调用mPackages.put(pkg.applicationInfo.packageName, pkg);将app对应的Package添加到mPackages中

15)将app中定义的providers添加到mProvidersByAuthority,services添加到mServices,

receivers添加到mReceivers,activities添加到mActivities

16)将app中定义的permissionGroups添加到mPermissionGroups,permissions添加到permissionMap,instrumentation添加到mInstrumentation

很多细节代码在前面章节都有过描述,这里就不再一一展开。

2.5 APK安装

先来了解一个服务:

DefaultContainerService

PMS安装过程中APK文件的拷贝,都要通过它来完成,所以在安装时,需要连接到该服务

以获取对应的BinderProxy来远程调用其功能。

接着介绍几个类:

1)    PackageHandler

对应变量mHandler,在PMS构造时会创建并绑定到HandlerThread,APK的安装相关代码会通过Message执行在这个工作线程。该Handler的主要Message ID如下:

ID

描述

INIT_COPY

将要安装APK信息放置于msg.obj并发送该Message到Handler,Handler执行后,会做两件事情:

1:判断当前是否已经连接到DefaultContainerService,如果未连接,调用connectToService进行连接

2:将要安装的APK信息添加到mPendingInstalls

3:如果mPendingInstalls长度为0,触发

MCS_BOUND消息

MCS_BOUND

依次从mPendingInstalls取出HandlerParams来进行安装

POST_INSTALL

安装成功后,会收到该消息来执行相关操作

2)    HandlerParams

  抽象类,如果要将安装操作通过INIT_COPY消息添加到PackageHandler,必须实现

  HandlerParams,并将对应的实例放置于msg.obj中,MCS_BOUND命令在处理时,会将msg.obj转换成HandlerParams,接着调用其函数startCopy来触发拷贝,拷贝过程中,会回调如下状态:

abstract void handleStartCopy() throws RemoteException;

abstract void handleServiceError();

abstract void handleReturnCode();

  APK拷贝对应的类为:

class InstallParams extends HandlerParams {

}

3)    InstallArgs

也是一个抽象类,对应的实现类有两个, FileInstallArgs和AsecInstallArgs,分别对应APK安装到系统存储和SD卡,他两在实际APK数据解析上,没任何区别,唯一不同的就是拷贝目录和文件目录操作存在差异,为了简单起见,后续我们只基于FileInstallArgs来分析。

HanderParams是为了给PackageHandler传递参数并触发拷贝和安装行为的,所以,它的接口更多的为了配合PackageHandler来设计的

FileInstallArgs则是拷贝的执行者,同时还处理安装前和安装后的一些逻辑处理等,它的设计,是跟PMS深度结合在一起的。

2.5.1安装接口描述

程序可以通过调用PMS. installPackage并传入APK文件路径,IPackageInstallObserver2对应的binder proxy, install Flags等来启动安装,IPackageInstallObserver2是用于给调用方反馈安装状态,install Flag指定安装命令,比如是否是替换安装等。

installPackage什么都没做,直接转到installPackageAsUser:

@Override

public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,

            int installFlags, String installerPackageName, VerificationParams verificationParams,

            String packageAbiOverride, int userId) {

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);

        final int callingUid = Binder.getCallingUid();

        enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");

        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {

            try {

                if (observer != null) {

                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);

                }

            } catch (RemoteException re) {

            }

            return;

        }

        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {

            installFlags |= PackageManager.INSTALL_FROM_ADB;

        } else {

            // Caller holds INSTALL_PACKAGES permission, so we're less strict

            // about installerPackageName.

            installFlags &= ~PackageManager.INSTALL_FROM_ADB;

            installFlags &= ~PackageManager.INSTALL_ALL_USERS;

        }

        UserHandle user;

        if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {

            user = UserHandle.ALL;

        } else {

            user = new UserHandle(userId);

        }

        verificationParams.setInstallerUid(callingUid);

        final File originFile = new File(originPath);

        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);

        final Message msg = mHandler.obtainMessage(INIT_COPY);

        msg.obj = new InstallParams(origin, observer, installFlags,

                installerPackageName, verificationParams, user, packageAbiOverride);

        mHandler.sendMessage(msg);

    }

函数开头先检查调用程序是否有INSTALL_PACKAGES权限,如果没有,直接抛出异常。

接着通过调用程度的user id来判断其是否被限制安装APK功能,如果是,直接返回

通过UID来判断是否是通过ADB来安装,接着基于传入的参数创建InstallParams实例并保存到INIT_COPY msg.obj中并发送到PackageHandler.

2.5.2完整的安装流程

安装从拷贝开始,拷贝由发送INIT_COPY到PackageHandler触发,完整流程图:

2.5.3安装包解析

从上面的流程可以看出,APK数据的解析,是通过installPackageLI来完成的,同样的,下面只基于新安装包这一情形来分析

看installPackageLI的代码后会发现,其实她实现的内容跟scanPackageL(File f…)基本上是一致的:

1)  创建PackageParser对象,接着调用parsePackage来解析apk清单数据,返回
PackageParser.Package对象pkg,pkg包含了apk原始的清单数据

2)  调用collectCertificates获取安装APK的签名数据

3)  调用installNewPackageLI并传入pkg

4)  调用scanPackageLI传入pkg进行apk数据扫描

5)  调用updateSettingsLI将apk数据更新到Settings

6)  updatePermissionsLPw同步系统权限数据

发布了46 篇原创文章 · 获赞 25 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/zhejiang9/article/details/52412410