理解包管理机制和PMS:

目录

PackageInstaller的初始化:

1.packageManager简介:

2.APK的文件结构和安装方式:

3.寻找PackageInstaller入口:

4.PackageInstallerActivity的解析:

5.PackageInstaller的初始化总结:

PackageInstaller安装APK的过程:

1.PackageInstaller中的处理:

1.1:InstallInstalling的onCreate方法:

1.2:InstallInstalling的onResume方法:

2.Java框架层的处理:

3.PackageInstaller安装APK总结:

PMS处理APK的安装过程:

1.PackageHandler处理安装的消息:

1.1:对INIT_COPY类型的消息进行处理:

1.2:对MCS_BOUND类型的消息进行处理:

1.2.1:消息不带object类型的参数:

1.2.2:消息带object类型的参数:

2.复制APK的处理:

3.PMS处理APK的安装:

3.1:installPackageLI方法的核心逻辑是:

4.总结:

PMS的创建过程:

1.SystemServer的处理部分:

2.PMS的构造方法:

2.1:开始阶段:

2.2:扫描系统阶段:

2.3:扫描Data分区阶段:

2.4:扫描结束阶段:

2.5:准备阶段:

APK的解析过程:

1.引入PackageParser:

2.PackageParser解析APK:

3.Package的数据结构:

3.1:补充:


包管理机制是Android中的重要机制,而包指的是apk,jar和so等文件,它们被加载到Android的内存中,由一个包转换为可执行的代码,需要一个机制来进行包的加载,解析和管理等等操作,这就是包管理机制。包管理机制由许多类组成,其中核心为PackageManagerService(PMS),它负责对包进行管理,我们先从PackageInstaller开始。

PackageInstaller的初始化:

1.packageManager简介:

与ActivityManager和AMS的关系类似,PMS也有一个对应的管理类PackageManager,用于向应用程序进程提供一些功能。PackageManager是一个抽象类。它的具体实现类为ApplicationPackageManager,ApplicationPackageManager中的方法会通过IPackageManager与PMS进行进程之间的通信,因此PackageManager所提供的功能最终都是由PMS来实现的,这么设计的原因是避免系统服务PMS被直接的访问,PackageManager提供了一些功能,主要有:

  • 获取一个应用程序的所有信息。
  • 获取四大组件的信息。
  • 查询permission的相关信息。
  • 获取包的相关信息。
  • 安装和卸载APK。

2.APK的文件结构和安装方式:

APK是AndroidPackage的缩写,即Android安装包,实际上是zip格式的压缩文件。在一般情况下,APK解压之后的文件结构为:

  • assert:存放原生资源文件,通过AssetManager类访问。
  • lib:存放库文件。
  • META-INF:保存应用的签名信息,签名信息可以验证apk文件的完整性。
  • res:存放资源文件。在res中除了raw子目录以外,其他的子目录都参与编译,这些子目录下的资源可以通过编译出来的R类在代码中访问。
  • AndroidManifest.xml:用来声明应用程序的包名称,版本,组件和权限等等数据。
  • classes.dex:Java源码编译之后生成的Java字节码文件。
  • resources.arsc:编译之后的二进制资源文件。

APK主要有四种安装的方式:

  • 通过adb命令安装。
  • 用户下载了APK,通过系统安装器PackageInstaller安装。PackageInstaller是系统内置的应用程序,用于安装和卸载应用程序。
  • 系统开机时安装系统应用。
  • 通过电脑或者手机上的应用商城自动安装。

其实这四种方式最后都是由PMS来进行处理的。

3.寻找PackageInstaller入口:

在Android7.0之前,我们可以通过下面的代码来安装指定的路径的APK:

Intent intent=new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://"+path),"application/vnd.android
.package-archive");
context.startActivity(intent);

如果在Android7.0或者更高的版本这么做,就会报FileUriExposedException异常。这是因为StricModeAPI政策禁止应用程序将file://Uri暴露给另一个应用程序,也就是如果包含file://Uri的intent离开了应用,就会报FileUriExpoasedException异常。为了解决这个问题,Google提供了FileProvider,它继承自contentProvider,使用它可以将file://Uri替换为content://Uri。所以不管是Android7.0以上还是以下,都会调用以下代码:

Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(xxxx,"application/vnd.android.package-archive");

其中Intent的Action属性为ACTION_VIEW,代表显示用户的数据,会根据用户的数据打开相应的activtiy。setDataAndType方法的1参是路径,2参是类型,上面的是APK类型。并且是隐式启动。接下来能隐式匹配到的Activity在Android8.0为InstallStartAndroid7.0为PackageInstallerActivity 。也就是在PackageInstaller的AndroidManifest.xml里的一个Activity,路径为:package/apps/PackageInstaller/AndroidManifest.xml。InstallStart是PackageInstaller中的入口Activity,当我们调用PackageInstaller来安装应用时,会跳转到InstallStart,并且调用它的onCreate方法。

package/apps/PackageInstaller/src/com/android/packageinstaller/InstallStart.java

onCreate方法:它首先会判断intent的action是否为CONFIRM_PERMISSIONS,接着判断packageUri是否为空,然后判断URI的scheme协议是否为content,如果是content就跳转到InstallStaging,如果不是就跳转到PackageInstallerActivity。在Android7.0以上,因为使用FileProvider来处理URI,所以会跳转到InstallStaging。

InstallStaging的onResume方法首先判断File类型的mStagedFile是否为null,是则创建一个mStagedFile,它是用于存储临时的数据的。接着调用StagingAsyncTask的execute方法,传入content协议的uri,启动StagingAsyncTask。

接下来跳转到StagingAsyncTask的doInBackground方法,它将packageUri的内容写入到mStagedFile中,如果写入成功,则在onPostExecute方法中跳转到PackageInstallerActivity中,并且将mStagedFile传进去。所以InstallStaging的作用主要是将content协议的uri转换为file协议,然后跳转到PackageInstallerActivity

4.PackageInstallerActivity的解析:

其实从功能上来说,PackageInstallerActivity才是应用安装器PackageInstaller的真正入口Activity。它的onCreate方法为:首先初始化安装所需要的各种对象,比如:PackageManager,IPackageManager,AppOpsManager和UserManager等等。其中它们的描述为:

类名描述
PackageManager用于向应用程序进程提供一些功能,最终由PMS实现
IPackageManager一个AIDL的接口,用于和PMS进行进程之间的通信
AppOpsManager用于权限的动态检测
PackageInstaller提供安装,升级和删除应用程序的功能
UserManager用于多用户管理

接着在onCreate方法中调用processPackageUri方法,该方法首先得到packageUri的scheme协议,再根据这个协议分别对package协议和file协议进行处理,如果不是这两个协议,那么就关闭PackageInstallerActivity并且返回false。我们来看file协议的处理过程,首先根据packageUri创建了一个新的file,在创建的过程中内部会调用packageParser的parsePackage方法解析这个file(这个file其实是apk文件),得到apk文件的包信息parsed,然后调用PackageParser.generatePackageInfo方法传入一系列参数得到PackageInfo。

packages/apps/PackageInstaller/src/com/android/packageinstaller/

PackageInstallerActivity.java

接着看onCreate方法的checkIfAllowedAndInitiateInstall方法,首先判断是否允许安装未知来源的APK或者APK不是未知来源,则调用initiateInstall方法来进行初始化安装。如果管理员限制未知来源的安装,那么就跳转到设置界面或者弹出提示对话框,否则调用handleUnknownSources方法来处理未知来源的APK。

initiateInstall方法首先调用了mPkgInfo.packageName方法得到包名,再调用mpm.getApplicationInfo方法获取应用程序的信息,接着调用startInstallConfirm方法,该方法首先确定初始化安装界面,并且界面上有确定和取消,还有安装APK需要的系统权限。而AppSecurityPermissions会提取APK的权限信息并且展示出来,这个负责展示的View是AppSecurityPermissions的内部类permissionItemView,并且将它添加到CaffeinatedScrollView中,展示安装该APK需要的系统权限。

5.PackageInstaller的初始化总结:

  1. 根据Uri的Scheme协议的不同,跳转到不同的界面,content协议跳转到InstallStart,其他的则跳转到PackageInstallerActivity。
  2. InstallStart将content协议的Uri转换为file协议,然后跳转到PackageInstallerActivity。
  3. PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议,则会解析出apk文件并且得到包信息packageInfo。
  4. PackageInstallerActivity会对未知来源的APK进行处理。如果允许安装或者APK不是未知来源,则初始化安装确认的界面,如果管理员限制未知来源,则跳转到设置界面或者弹出提示对话框。

PackageInstaller安装APK的过程:

1.PackageInstaller中的处理:

紧接着PackageInstallerActivity的onCreate方法的checkIfAllowedAndInitiateInstall方法中的initiateInstall方法的startInstallConfirm方法。上面写到它会展示一个安装界面给用户,用户想要安装这个应用程序,在点击确定之后,会调用PackageInstallerActivity的onClick方法。在该方法中对确定和取消按钮进行了处理,我们来看确定按钮的处理,确定按钮会调用startInstall方法startInstall方法用于跳转到InstallInstalling的Activity,并且关闭当前的PackageInstallerActivity

1.1:InstallInstalling的onCreate方法:

InstallInstalling主要用于向包管理器发送包的信息并且处理包管理的问题,它的onCreate方法会对package和content协议的Uri进行处理,我们来看content协议的Uri处理部分。如果savedInstanceState不为null,则获取之前保存的mSessionId和mInstallId,前者是安装包的会话ID,后者是等待的安装事件的ID。接着根据mInstallId向InstallEventReceiver的addObserver方法注册一个观察者,那么launchFinishBasedOnResult会接收到安装事件的回调,无论安装成功与否,都会关闭当前的Activity(InstallInstalling)。

如果savedInstanceState为null,那么会通过packageInstaller的SessionParams创建一个SessionParams,代表安装会话的参数,然后对APK进行轻量级的解析,并且把解析的参数赋值给SessionParams。接着向InstallEventReceiver的addObserver方法注册一个观察者并且还会返回一个新的mInstallId。然后调用PackageInstaller的createSession方法,它内部会通过IPackageInstaller与PackageInstallerService进行进程之间的通信,最终调用的是PackageInstallerService的createSession方法来创建并且返回mSession。

1.2:InstallInstalling的onResume方法:

onResume方法首先通过installer的getSessionInfo方法得到SessionInfo,它代表安装会话的详细信息。接着如果SessionInfo不为null并且不是活动的,就创建并且执行InstallingAsyncTask。InstallingAsyncTask的doInBackground方法会根据APK的uri,将APK的信息通过I/O流的方式写入PackageInstaller.Session中。而InstallingAsyncTask的onPostExecute方法会通过PendingIntent.getBroadcast方法创建一个PendingIntent,并且通过session的commit方法将PendingIntent的IntentSender发送出去。session的commit方法内部调用了IPackageInstallerSession类型的mSession对象的commit方法,最终它调用的是PackageInstallerSession的commit方法。而IPackageInstallerSession说明了要进行进程之间的通信。这样代码就来到了Java的框架层。

packages/apps/PackageInstaller/src/com/android/packageinstaller/installing.java

2.Java框架层的处理:

PackageInstallerSession的commit方法会将发送过来的包信息封装为PackageInstallObserverAdapter,它在PMS中被定义。接着调用mHandler的obtainMessage方法向Handler发送一个类型为MSG_COMMIT的消息。

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

该消息在handleMessage方法中被处理,首先通过msg的obj获取IPackageInstallerObserver2类型的观察者mRemoteObserver,接着调用commitLocked方法,该方法主要做了:调用PMS的installStage方法,这样代码的逻辑就进入了PMS的代码逻辑中。如果commitLocked方法出现异常,则调用dispatchSessionFinished方法,该方法调用了IPackageInstallObserver2的onPackageInstalled方法将异常回调给PackageInstallObserverAdapter。

3.PackageInstaller安装APK总结:

  1. 将APK的信息通过I/O流的形式写入到PackageInstaller.Session中。
  2. 通过调用PackageInstaller.Session的commit方法,将APK的信息交给PMS处理。

PMS处理APK的安装过程:

APK的信息交给PMS之后,PMS会通过向PackageHandler发送消息来驱动APK的复制和安装工作。

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

1.PackageHandler处理安装的消息:

接着来看PMS的installStage方法,首先通过mHandler.obtainMessage创建了类型为INIT_COPY的消息。接着创建了Installparams,它代表对应的包的安装数据。然后调用mHandler的sendMessage方法把Installparams发送出去。

1.1:对INIT_COPY类型的消息进行处理:

处理INIT_COPY类型的消息在PackageHandler的doHandlerMessage方法中,其中PackageHandler继承自Handler,它被定义在PMS中,而doHandlerMessage方法用于处理各种类型的消息。我们来看对INIT_COPY消息的处理过程:首先通过mBound判断是否绑定了DefaultContainerService,默认值为false,它是用于检查和复制可移动文件的服务,这个是一个比较耗时的工作,因此DefaultContainerService没有和PMS运行在同一个进程中,它运行在com.android.defcontainer进程中,通过IMediaContainerService和PMS进行IPC通信。如果没有绑定DefaultContainerService,那么后续调用connectToService方法用于绑定。如果绑定了调用mHandler的sendEmptyMessage方法,并且发送一个MCS_BOUND类型的消息,触发处理安装的请求。

connectToService方法中在DefaultContainerService绑定成功之后会把mBound设置为true,而bindServiceAsUser方法会传入mDefContainerConn,bindServiceAsUser方法会传入mDefContainerConn。

在建立服务的连接之后,就会调用的是onServiceConnected方法,该方法调用了mHandler.sendMessage方法发送了一个MCS_BOUND类型的消息,与mHandler的sendEmptyMessage方法不同的是,它多了一个object类型的参数。接下来会对这两种情况进行分析。

1.2:对MCS_BOUND类型的消息进行处理:

1.2.1:消息不带object类型的参数:

也就是mHandler的sendEmptyMessage方法发送的MCS_BOUND类型的消息,那么就会触发mContainerService==null这条分支,它首先会判断有没有绑定DefaultContainerService,这里应该是绑定了,所以会告知用户等待系统绑定服务。

1.2.2:消息带object类型的参数:

如果消息带object类型的参数的话,那么会触发mPendingInstalls.size()>0的分支,得到安装请求队列中的第一个请求HandlerParams,在HandlerParams不为null的情况下,调用HandlerParams的startCopy方法,用于复制APK的流程。如果安装成功的话,会删除本次的安装请求。如果安装成功之后,安装请求队列还有的话,那么还会调用mHandler.sendEmptyMessage方法发送一个MCS_BOUND类型的消息,直到安装请求队列为空。如果没有安装请求的话,则发送解绑服务的请求。

2.复制APK的处理:

HandlerParams是PMS中的抽象类,它的实现类为PMS的内部类InstallParams。HandlerParams的startCopy方法。在startCopy方法中有一个mRetries,它是用于记录startCopy方法的调用次数,调用startCopy方法时会自动加1,直到尝试的次数大于MAX_RETRIES则放弃这个安装请求。如果尝试的次数大于MAX_RETRIES的话,还会调用mHandler的sendEmptyMessage方法发送一个MCS_GIVE_UP类型的消息,并且将本次的安装请求从安装请求队列mPendingInstalls中移除。如果尝试次数没有大于MAX_RETRIES的话,则调用抽象方法handlerStartCopy方法,它的实现在InstallParams中。

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

handlerStartCopy方法的代码逻辑很多,相关的有:通过IMediaContainerService跨进程调用DefaultContainerService的getMinimalPackageInfo方法,该方法会轻量的解析APK并且得到APK的少量信息,轻量解析的原因是不需要获取APK的全部信息,而APK的少量信息会被封装在PackageInfoLite中。然后确定APK的安装位置。接着调用createInstallArgs方法传入InstallParams来创建InstallArgs对象。最后调用InstallArgs类型的args对象的copyApk方法进行安装。

其中InstallArgs是一个抽象类,它定义了APK的安装逻辑,比如复制和重命名APK等等,在InstallArgs中有3个子类,都被定义在PMS中。分别是:

  • FileInstallArgs:用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(data分区)
  • AsecInstallArgs:用于处理安装到ASEC(即SD卡)的APK
  • MoveInstallArgs:用于处理已经按照APK在存储中移动的逻辑

不同的InstallArgs的子类有不同的处理方法,这里以FilestallArgs为例。FileInstallArgs的copyApk方法直接返回了FileInstallArgs的doCopyApk方法。该方法会调用allocateStageDirLegacy方法创建临时文件的存储目录,比如/data/app/vmd118300.tmp,其中的118300是按照的sessionId。接着调用IMediaContainerService类型的imcs对象的copyPackage方法通过IMediaContainerService跨进程调用了DefaultContainerService的copyPackage方法,将DefaultContainerService所在的进程中将APK复制到这个临时存储的目录中。到这里,APK的复制已经完成,接下来就是APK的安装过程了。

3.PMS处理APK的安装:

在HandlerParams的startCopy方法调用完handlerStartCopy方法完成复制之后,接着调用handleReturnCode方法,它的实现在InstallParams中。在handleReturnCode方法中只调用了processPendingInstall方法,该方法首先进程APK的状态是否正常,安装环境是否可靠。安装调用的是installPackageTracedLI方法,其内部会调用PMS的installPackageLI方法。安装后进行收尾的是doPostInstall方法。如果安装不成功的话,则删除安装相关的目录和文件。

3.1:installPackageLI方法的核心逻辑是:

  1. 创建PackageParser,再调用PackageParser的parsePackage方法解析APK。
  2. 检查APK是否存在,如果存在就获取之前没有被改名前的包名,并且赋值给PackageParser.Package类型的pkg,然后把replace设置为true,表示替换安装。
  3. 通过ps!=null判断,如果settings中存在要安装的APK信息,就说明之前安装过该APK,则需要校验APK的签名信息,确保进行替换安装是安全的。
  4. 重命名临时文件,通过doRename方法。
  5. 系统APP的更新安装会有两个限制,分别是:系统APP不能在SD卡上进行替换安装和系统APP不能被instant APP替换。
  6. 根据设置的replace进行判断,如果是替换安装,就调用replacePackageLIF方法,该方法内部还会对系统APP和非系统APP进行区分处理;如果是安装新的APK,就会调用installNewPackageLIF方法。

以installNewPackageLIF方法为例子,installNewPackageLIF方法主要做了:

  1. 扫描APK,通过scanPackageTracedLI方法将APK的信息存储在PackageParser.Package类型的newPackage中,其中一个Package的信息包含了一个base APK以及0个或者多个splitAPK。
  2. 通过updateSettingLI方法更新APK对应的Settings信息,其中Settings用于保存所有包的动态设置。
  3. 如果安装成功,就调用prepareAppDataAfterInstallLIF方法为新安装的应用程序准备数据,如果安装失败,就调用deletePackageLIF方法删除APK。

4.总结:

PMS安装APK的步骤,主要有:

  1. PackageInstaller安装APK时会将APK的信息交给PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。
  2. PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,并且完成APK复制等工作。
  3. 复制完APK之后,开始进行安装APK的流程,包括安装前的检查,安装APK和安装后的收尾工作。

PMS的创建过程:

PMS的创建过程可以大致分为两个部分,分别是systemserver的处理部分和PMS的构造方法。

1.SystemServer的处理部分:

SystemServer进程是用来创建系统服务的,而PMS是在SystemServer进程中被创建的,具体是SystemServer进程的main方法的startBootstrapServices方法创建的,该方法用于启动引导服务,而PMS也是属于引导服务的一员。熟悉的AMS属于引导服务,WMS属于其他服务。

frameworks/base/services/java/com/android/server/SystemServer.java

startBootstrapServices方法中创建PMS的有关部分有:通过SystemProperties的get方法获取init.rc的void.decrypt属性,接着判断该属性是否为trigger_restart_min_framework,如果是则说明我们加密了设备,表示只运行核心程序,这是为了创建一个极简的启动环境。然后调用PMS的main方法创建PMS。接着通过PMS的isFirstBoot方法获取boolean类型的变量mFirstBoot,它用于表示PMS是否首次被启动,而mFirstBoot还是后续WMS创建时需要的参数,这也说明了系统服务之间是有依赖关系的。

2.PMS的构造方法:

PMS的main方法主要有两个作用,一个是用于创建PMS对象,一个是将PMS注册到ServiceManager中。

PMS的构造方法,主要分为5个阶段,每个阶段都会打印出相应的EventLog(EventLog用于打印Android系统的事件日志),如下所示:

  1. BOOT_PROGRESS_PMS_START(开始阶段)。
  2. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START(扫描系统阶段)。
  3. BOOT_PROGRESS_PMS_DATAS_CAN_START(扫描Data分区阶段)。
  4. BOOT_PROGRESS_PMS_SCAN_END(扫描结束阶段)。
  5. BOOT _PROGRESS_PMS_READY (准备阶段)

2.1:开始阶段:

在开始阶段,PMS的构造方法中会获取一些包管理所需的属性,并且创建了很多PMS中的关键对象并且赋值给PMS中的成员变量。成员变量有:

  • mSetings:用于保存所有包的动态设置。mSettings的addSharedUserLPw方法将系统进程的sharedUserld添加到mSettings中,sharedUserld用于进程间共享数据,比如两个App之间的数据是不共享的,如果它们有了共同的sharedUserld,就可以运行在同一个进程中共享数据。
  • minstaller:Installer继承自SystemService,和PMS、AMS一样是系统服务,PMS的很多操作都是由Installer来完成的,比如APK的安装和卸载。在Installer内部,通过IInstalld和installd进行Binder通信,由位于Native层的 installd来完成具体操作。
  • systemConfig:用于得到全局系统的配置信息,比如系统的权限就可以通过SystemConfig来获取。
  • mPackageDexOptimizer:Dex优化的工具类。
  • mHandler (PackageHandler类型):PackageHandler继承自Handler,通过创建PackageHandler实例时传入mHandlerThread的getLooper方法,使它绑定了后台线程ServiceThread的消息队列。PMS通过PackageHandler驱动APK的复制和安装工作。如果PackageHandler处理的消息队列过于繁忙,则有可能导致系统卡住,因此调用Watchdog.getInstance().addThread方法将它添加到Watchdog的检测集中。
  • Watchdog主要有两个用途:一个是定时检测系统关键服务(AMS和WMS等)是否可能发生死锁,还有一个是定时检测线程的消息队列是否长时间处于工作状态(可能阻塞并等待了很长时间)。如果出现上述问题,则Watchdog会将日志保存起来,必要时还会杀掉自己所在的进程,也就是SystemServer进程。
  • sUserManager(UserManagerService类型):多用户管理服务。
  • 除了这些成员变量,还有加了两个锁,分别是:mInstallLockmPackages,前者是安装APK时需要的锁,保护对installd的访问;后者是更新APK时需要的锁,保护内存中已经解析的包信息等等内容。
  • Environment的getDataDirectory方法以及后续的一系列方法,创建了一些Data分区中的子目录。
  • 通过mSettings的readLpw方法传入sUerManager的getUsers方法,来解析packages.xml等文件的信息,并将其保存到Settings的对应字段中。其中packages.xml中记录系统中所有安装的应用信息,包括基本信息、签名和权限。如果packages.xml中有安装的应用信息,那么readLPw方法会返回true,然而mFirstBoot的值为false,说明PMS不是首次被启动。

2.2:扫描系统阶段:

先介绍一下:/system可以称为System分区,其中主要存储Google和其他的厂商提供的Android系统相关的文件和框架。Android系统架构可以分为:应用层,应用框架层,系统运行库层,硬件抽象层和Linux内核层。除了Linux内核层在Boot分区以外,其他的层的代码都在System分区。

system分区的部分子目录
目录含义
app存放系统app,包括Google内置的app,还有厂商提供的app
framework存放应用框架层的jar包
priv-app存放特权app
lib存放so文件
fonts存放系统字体文件
media存放系统的各种声音

接着来看系统的扫描阶段主要工作有3点:

  1.  创建/system的子目录,比/system/framework , /system/priv-app 和/system/app等等。
  2. 扫描系统文件,比如:/vendor/overlay、/system/framework和/system/app等目录文件。
  3. 对扫描到的系统文件进行后续处理。

这里主要说第三点:一次OTA升级对于一个系统APP会出现3种情况:

  • 这个系统APP没有更新。
  • 这个系统APP有更新。
  • 在新的OTA版本中,这个系统APP已经被删除。

2.3:扫描Data分区阶段:

先介绍一下:/data可以被称为Data分区,它用来存储所有的用户个人数据和配置文件。

Data分区的部分子目录
目录含义
app存储用户自己安装的APP
data存储所有已经安装的APP数据,每个APP都有自己单独的目录
app-privateAPP的私有存储空间
app-lib存储所有的APP的JNI库
system存储系统的配置文件
anr用于存储ANR发生时系统生成的trace.txt文件

接着来看扫描Data分区阶段主要工作有3点:

  1. 扫描/data/app 和/data/app-private目录下的文件。
  2. 遍历possiblyDeletedUpdatedSystemApps列表,在扫描Data分区阶段代码中,如果这个系统App的包信息不在PMS的变量mPackages中,则说明其是残留的App信息,后续会删除它的数据。如果这个系统App的包信息在mPackages中,则说明其存在于Data分区中,不属于系统App,那么移除其系统权限。
  3. 遍历mExpectingBetter列表。根据系统App所在的目录设置扫描的解参数。而mSettings的enableSystemPackageLPw方法内部会将packageName对应的包设置数据(PackageSetting)添加至mSettings的mPackages中。scanPackageTracedLI方法扫描系统App的升级包。最后清除mExpectingBetter 列表。

2.4:扫描结束阶段:

扫描结束阶段的主要工作有:

  1. 如果当前的平台SDK版本与上次启动的SDK版本不同,则重新更新APK的授权。也就是if(ver.sdkVersion!=mSdkVersion)后续。
  2. 如果是第一次启动或者是Android M升级之后的第一次启动,则需要初始化所有的用户定义的默认首选APP。也就是if(!onlyCore&&(mPromoteSystemApps||mFirstBoot))后续。
  3. OTA升级之后的第一次启动,会清除代码缓存的目录。也就是if(mIsUpgrade&&!onlyCore)后续。
  4. 把settings的内容保存到packages.xml中,这样以后PMS再创建时就会读到之前保存到settings的内容。

2.5:准备阶段:

准备阶段主要先创建了PackageInstallerService,它是用于管理安装会话的服务,还会给每次的安装过程分配一个SessionId。接着调用Runtime.getRuntime().gc方法进行一次垃圾的收集。然后调用LocalService的addService方法把PackageManagerInternalImpl添加进去,LocalService用于存储运行在当前进程中的本地服务。

APK的解析过程:

PackageParser类用于在APK的安装过程中解析APK。

1.引入PackageParser:

Split APK机制:Android5.0引入了这个机制,其目的是解决65536限制以及APK安装包越来越大的问题。Split APK机制可以将一个APK拆分为多个独立的APK。在引入该机制之后,APK有以下两种分类:

  • Single APK:一个完整的APK安装文件,即base APK。Android称其为Monolithic。
  • Mutiple APK:在一个文件的目录中安装文件,其内部有多个被拆分的APK。这些APK由一个base APK和一个或者多个split APK组成。Android称其为Cluster。

Android世界中有很多包,比如:应用程序的APK,Android运行环境的jar包和组成Android系统的各种动态库so等等。由于包的种类和数量比较多,这就需要进行包的管理,但是包管理需要在内存中进行,而这些包都是以静态的文件形式存在的,所以就需要一个工具类将这些包转换为内存中的数据结构,这个工具类就是包解析器PackageParser。在PMS处理APK的安装的installPackageLI方法中有创建PackageParser,再调用PackageParser的parsePackage方法解析APK。

frameworks/base/core/java/android/content/pm/PackageParser.java

2.PackageParser解析APK:

parsePackage方法首先判断要解析的packageFile是Mutiple APK还是Single APK。如果是Mutiple APK就调用parseClusterPackage方法来解析;如果是Single APK就调用parseMonolithicPackage方法来解析。这里以parseClusterPackage方法为例子。


parseClusterPackage方法:

  1. 首先调用了parseClusterPackageLite方法用于轻量级解析目录文件。之所以要轻量级解析,是因为解析APK是一个复杂且耗时的工作,这里的逻辑并不需要APK的所有信息。parseClusterPackageLite方法内部会通过parseApkLite方法解析每个Mutiple APK,得到每个Mutiple APK对应的ApkLite(轻量级APK信息),然后将这些ApkLite封装为一个PackageLite(轻量级包信息)并且返回。
  2. 然后看parseClusterPackage方法的if(mOnlyCoreApps&&!lite.coreApp),其中mOnlyCoreApps用于指示PackageParser是否只解析核心应用,核心应用指的是AndroidManifest中属性coreApp的值为true,只解析核心应用是为了创建一个极简的启动环境。而mOnlyCoreApps是创建PMS时一路传递过来的,如果我们加密了设备,mOnlyCoreApps的值为true。另外可以通过PackageParser的setOnlyCoreApps方法来设置mOnlyCoreApps的值。而litecoreApp表示当前是否包含核心应用。
  3. 接下来的parseBaseApk方法用于解析base APK。
  4. lite.splitNames.length方法用于获取split APK的数量,根据这个数量,在后续的parseSplitApk方法中依次的来解析每个split APK。

继续来看parseBaseApk方法:首先调用apkPath的substring方法,如果APK的路径以/mnt/expaand/开头,那么就截取该路径来获取volumeUuid。接着给Package类型的pkg对象通过setXXXX方法标识一系列例如:解析后的package,存储卷UUID等等。然后调用parseBaseApk的一个重载方法。该方法首先创建了Package对象,接着通过res的obtainAttributes方法从资源中提取了自定义属性集com.android.internal.R.styleable.AndroidManifest并且得到TypedArray。然后通过这个TypedArray读取APK的AndroidManifest中的versionCode,revisionCode和versionName的值,并且赋值给Package的对应的属性。接着通过parser的getAttributeBooleanValue方法读取APK的AndroidManifest中的coreApp的值。最后调用parseBaseApkCommon方法,用于解析APK的AndroidManifest中的各个标签,比如:application标签的解析方法为parseBaseApplication方法。

3.Package的数据结构:

包被解析之后,最终显示内存中的是Package,Package是PackageParser的内部类,在Package中有很多列表,例如:activities列表中存储了类型为Activity的对象,而这个Activity不是常用的Activity,而是PackageParser的静态内部类,其他的列表也是如此。

3.1:补充:

  • Package中有许多组件,比如Activity,Provider和Permission等等,它们都继承于基类Component。
  • 每一个组件都包含有一个info数据,比如Activity类中包含了成员变量ActivityInfo,这个ActivityInfo才是真正的Activity数据。
  • 四大组件的标签内可能包含<intent-filter>,其用来过滤intent的信息,因此需要IntentInfo来保存组件的Intent信息,组件基类Component依赖于IntentInfo,IntentInfo有三个子类,即ActivityIntentInfo,ServiceIntentInfo和ProviderIntentInfo,不同的组件依赖的IntentInfo会有所不同,比如:Activity继承自Component<ActivityIntentInfo>,Permission继承自Component<IntentInfo>。
  • 最终解析的数据将会封装到Package中,除此之外,在解析的过程中还有两个轻量级数据结构,即ApkLite和PackageLite。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值