PackageManagerService主要是一个包的管理服务,在开机的时候会解析以前保存的一些安装包的相关数据,android运行过程中新安装的apk也会保存到PackageManagerService的相关变量中,也会写到相关的文件中永久保存。

首先看一下它的总体流程

PackageManagerService也是由SystemServer启动的

PackageManagerService 的实现是以aidl方式实现的, 我们可以看到继承了 IPackageManager.Stub,其aidl文件为frameworks\base\core\java\android\content\pm\IPackageManager.aidl

主要是负责管理apk包,安装apk的时候负责解析该apk包的manifest.xml,把其中包含的activity,service等添加到packagemanageservice中,以便运行该包的时候就能直接从packagemanageservice中获取该apk的相关信息,还会监控/system/app等目录,当我们把一个apk放到该目录时会自动对其进行安装(调用AppDirObserver的onEvent)

它的启动过程主要涉及以下几个方面

1、建立 java 层的 installer 与 c 层的 installd 的 socket 联接,使得在上层的 install,remove,dexopt等功能最终由installd在底层实现

这里涉及到socket的server和client端,在系统启动时候会启动一个installd的程序,init.rc中

  1. service installd /system/bin/installd
  2. socket installd stream 600 system system

有一个socket名字是installd

这个可执行文件的代码在/framework/base/cmds/installd目录下面,比较简单,主要是监听socket上是否有数据来,有的话解析数据,执行相应的命令

在packagemanageservice中则会连接到相应这个socket,然后有需要的操作时,把相应的操作代码发到installd,由其进行解析操作

2、 建立PackageHandler消息循环,用于处理apk安装请求如adbinstall packageinstaller安装apk时就会发送消息

新建了一个HandlerThread的线程,并在其run函数中新建了一个Looper,把它设为PackageHandler,然后就可以利用它进行消息的处理

3、解析/system/etc/permission下的xml文件,主要是platform.xml,建立permission和gid之间的关系,可以指定一个权限与几个组对应,当一个apk被授予这个权限时它也同时属于这几个组,readPermission(parser, perm);给一些底层用户分配一些权限,如shell授予各种permission,把一个权限赋予一个uid,当apk使用这个uid运行时,就具备了这个权限系统增加的一些应用需要link的扩展的jar库,系统每增加一个硬件,都要添加相应的featrue,将解析结果放入mAvailableFeatures

看一下platform.xml中的部分

  1. .......
  2. <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
  3. <group gid="cache" />
  4. </permission>
  5. <!-- RW permissions to any system resources owned by group 'diag'.
  6. This is for carrier and manufacture diagnostics tools that must be
  7. installable from the framework. Be careful. -->
  8. <permission name="android.permission.DIAGNOSTIC" >
  9. <group gid="input" />
  10. <group gid="diag" />
  11. </permission>
  12. ......
  13. <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
  14. <assign-permission name="android.permission.SEND_SMS" uid="shell" />
  15. <assign-permission name="android.permission.CALL_PHONE" uid="shell" />
  16. <assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
  17. <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" />
  18. <assign-permission name="android.permission.READ_CALENDAR" uid="shell" />
  19. .......
  20. <library name="android.test.runner"
  21. file="/system/framework/android.test.runner.jar" />
  22. <library name="javax.obex"
  23. file="/system/framework/javax.obex.jar"/>
  24. <feature name="android.hardware.wifi" />

其中readPermission主要是

1、读取permission name添加到mSettings.mPermissions

2、读取gid添加到mSettings.mPermissions

readPermissionsFromXml:

permission

a、读取permission name添加到mSettings.mPermissions

b、读取gid添加到mSettings.mPermissions

assign-permission

a、设置相应uid所具有的权限,保存到mSystemPermissions

library

a、.jar包保存到mSharedLibraries

feature

a、  硬件相关信息保存到mAvailableFeatures

4、检查/data/system/packages.xml是否存在,里面记录了系统的ppermission,以及每个apk的name,codePath,flags,ts,version,userid等,这些信息主要是通过apk安装的时候解析AndroidManifest.xml获取到的,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中,当有apk安装,升级,删除时会更新这个文件

readLP

解析/data/system/packages.xml

last-platform-version :最后使用的内外部存储器的sdk版本

permissions:构造权限结构BasePermission添加到mPermissions

package:解析每个已经安装apk的name,codePath,sharedUserId,userId,version等,调用addPackageLP构建PackageSetting并添加到mPackages

shared-user:readSharedUserLP通过addSharedUserLP添加一个SharedUserSetting结构,再通过readGrantedPermissionsLP读取给这个userId赋予的权限

writeLP

先把以前的packages.xml备份为packages-backup.xml,再把文件mSettingsFilename和XmlSerializer对象关联,再相关要写入文件的值先写入序列化对象,把相关信息写入序列化对象,再通过序列化对象写入文件

看一下package.xml

  1. <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
  2. <packages>
  3. <last-platform-version internal="9" external="0" />
  4. <permission-trees />
  5. <permissions>
  6. <item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1" />
  7. <item name="android.permission.CLEAR_APP_USER_DATA" package="android" protection="2" />
  8. <item name="android.permission.SHUTDOWN" package="android" protection="2" />
  9. <item name="android.permission.BIND_INPUT_METHOD" package="android" protection="2" />
  10. ...................
  11. <package name="com.android.settings" codePath="/system/app/XJNTSettings.apk" nativeLibraryPath="/data/data/com.android.settings/lib" flags="1" ft="11b7e237e00" it="11b7e237e00" ut="11b7e237e00" version="1" userId="10020">
  12. <sigs count="1">
  13. <cert index="0" />
  14. </sigs>
  15. </package>
  16. ..............
  17. <shared-user name="android.uid.shared" userId="10000">
  18. <sigs count="1">
  19. <cert index="1" />
  20. </sigs>
  21. <perms>
  22. <item name="android.permission.READ_SYNC_STATS" />
  23. <item name="android.permission.USE_CREDENTIALS" />
  24. <item name="android.permission.INTERNET" />
  25. <item name="android.permission.SUBSCRIBED_FEEDS_READ" />
  26. <item name="android.permission.READ_CONTACTS" />
  27. <item name="android.permission.GET_ACCOUNTS" />
  28. <item name="android.permission.WRITE_CONTACTS" />
  29. <item name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
  30. </perms>
  31. </shared-user>
  32. ...............
  33. <preferred-activities>
  34. <item name="tv.ipanel.join.xjnt.homefinal/tv.ipanel.join.xjnt.home.XJNTHomeActivity" match="100000" set="2">
  35. <set name="tv.ipanel.join.xjnt.home/.XJNTHomeActivity" />
  36. <set name="tv.ipanel.join.xjnt.homefinal/tv.ipanel.join.xjnt.home.XJNTHomeActivity" />
  37. <filter>
  38. <action name="android.intent.action.MAIN" />
  39. <cat name="android.intent.category.HOME" />
  40. <cat name="android.intent.category.DEFAULT" />
  41. </filter>
  42. </item>
  43. </preferred-activities>

5、检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要则通过dexopt进行优化

这里面主要是调用mInstaller.dexopt进行相应的优化

6、启动AppDirObserver线程往中监测/system/framework,/system/app,/data/app/data/app-private目录的事件,主要监听add和remove事件,对于目录监听底层通过innotify机制实现,inotify是一种文件系统的变化通知机制如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持,当有add event时调用scanPackageLI(File,int,int)处理,当有remove
event时调用removePackageLI处理

ObserverThread中有一段静态程序块(当一个类需要在被载入时就执行一段程序,这样可以使用静态程序块)

  1. static {
  2. s_observerThread = new ObserverThread();
  3. s_observerThread.start();
  4. }

而它的run函数

  1. public void run() {
  2. observe(m_fd);
  3. }

observer是个native函数,m_fd是ObserverThread初始化时候赋值的

  1. public ObserverThread() {
  2. super("FileObserver");
  3. m_fd = init();
  4. }

看一下这几个native函数

init比较简单,直接调用inotify_init返回一个句柄标识

  1. static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd)
  2. {
  3. #ifdef HAVE_INOTIFY
  4. char event_buf[512];
  5. struct inotify_event* event;
  6. while (1)
  7. {
  8. int event_pos = 0;
  9. int num_bytes = read(fd, event_buf, sizeof(event_buf));
  10. if (num_bytes < (int)sizeof(*event))
  11. {
  12. if (errno == EINTR)
  13. continue;
  14. LOGE("***** ERROR! android_os_fileobserver_observe() got a short event!");
  15. return;
  16. }
  17. while (num_bytes >= (int)sizeof(*event))
  18. {
  19. int event_size;
  20. event = (struct inotify_event *)(event_buf + event_pos);
  21. jstring path = NULL;
  22. if (event->len > 0)
  23. {
  24. path = env->NewStringUTF(event->name);
  25. }
  26. env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
  27. if (env->ExceptionCheck()) {
  28. env->ExceptionDescribe();
  29. env->ExceptionClear();
  30. }
  31. if (path != NULL)
  32. {
  33. env->DeleteLocalRef(path);
  34. }
  35. event_size = sizeof(*event) + event->len;
  36. num_bytes -= event_size;
  37. event_pos += event_size;
  38. }
  39. }
  40. #endif // HAVE_INOTIFY
  41. }

observe则从句柄中读取事件,然后调用java层函数onEvent进行处理,看一下java层的onEvent函数

  1. public void onEvent(int wfd, int mask, String path) {
  2. // look up our observer, fixing up the map if necessary...
  3. FileObserver observer = null;
  4. synchronized (m_observers) {
  5. WeakReference weak = m_observers.get(wfd);
  6. if (weak != null) {  // can happen with lots of events from a dead wfd
  7. observer = (FileObserver) weak.get();
  8. if (observer == null) {
  9. m_observers.remove(wfd);
  10. }
  11. }
  12. }
  13. // ...then call out to the observer without the sync lock held
  14. if (observer != null) {
  15. try {
  16. observer.onEvent(mask, path);
  17. } catch (Throwable throwable) {
  18. Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable);
  19. }
  20. }
  21. }

调用observer的onEvent继续处理,这里的AppDirObserver

  1. public void onEvent(int event, String path) {
  2. String removedPackage = null;
  3. int removedUid = -1;
  4. String addedPackage = null;
  5. int addedUid = -1;
  6. synchronized (mInstallLock) {
  7. String fullPathStr = null;
  8. File fullPath = null;
  9. if (path != null) {
  10. fullPath = new File(mRootDir, path);
  11. fullPathStr = fullPath.getPath();
  12. }
  13. if (Config.LOGV) Log.v(
  14. TAG, "File " + fullPathStr + " changed: "
  15. + Integer.toHexString(event));
  16. if (!isPackageFilename(path)) {
  17. if (Config.LOGV) Log.v(
  18. TAG, "Ignoring change of non-package file: " + fullPathStr);
  19. return;
  20. }
  21. // Ignore packages that are being installed or
  22. // have just been installed.
  23. if (ignoreCodePath(fullPathStr)) {
  24. return;
  25. }
  26. PackageParser.Package p = null;
  27. synchronized (mPackages) {
  28. p = mAppDirs.get(fullPathStr);
  29. }
  30. if ((event&REMOVE_EVENTS) != 0) {
  31. if (p != null) {
  32. removePackageLI(p, true);
  33. removedPackage = p.applicationInfo.packageName;
  34. removedUid = p.applicationInfo.uid;
  35. }
  36. }
  37. if ((event&ADD_EVENTS) != 0) {
  38. if (p == null) {
  39. p = scanPackageLI(fullPath,
  40. (mIsRom ? PackageParser.PARSE_IS_SYSTEM
  41. | PackageParser.PARSE_IS_SYSTEM_DIR: 0) |
  42. PackageParser.PARSE_CHATTY |
  43. PackageParser.PARSE_MUST_BE_APK,
  44. SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
  45. System.currentTimeMillis());
  46. if (p != null) {
  47. synchronized (mPackages) {
  48. updatePermissionsLP(p.packageName, p,
  49. p.permissions.size() > 0, false, false);
  50. }
  51. addedPackage = p.applicationInfo.packageName;
  52. addedUid = p.applicationInfo.uid;
  53. }
  54. }
  55. }
  56. synchronized (mPackages) {
  57. mSettings.writeLP();
  58. }
  59. }
  60. if (removedPackage != null) {
  61. Bundle extras = new Bundle(1);
  62. extras.putInt(Intent.EXTRA_UID, removedUid);
  63. extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
  64. sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
  65. extras, null);
  66. }
  67. if (addedPackage != null) {
  68. Bundle extras = new Bundle(1);
  69. extras.putInt(Intent.EXTRA_UID, addedUid);
  70. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
  71. extras, null);
  72. }
  73. }

这里判断是add还是remove事件,如果是add则调用scanPackageLI安装该apk,如果是remove则调用removePackageLI删除

另外还有一个startWatching是开始监听,其native函数主要是调用inotify_add_watch(fd, path, mask)对指定目录进行监听

7、apk解析

对于以上几个上目录下的apkg逐个解析,主要是解析每个apk的AndroidManifest.xml文件,处理asset/res等资源文件,建立起每个apkr 配置结构信息,

调用parsePackage对apk进行解析,并把相应的数据保存到Package中

8、将解析出的Package的相关信息保存到相关全局变量,还有文件(上面已经提及)

这里主要是上面 PackageManagerService流程流程中的这一段

主要进行:

a、  查找该apk依赖的库是否存在

b、  查找该apk共享的uid是否存在

c、  判断该包是否已经存在,存在的话需要做一些处理

d、  查看它的Setting结构是否存在,不存在则创建它

e、  签名认证

f、  新应用的provider是否与已有的冲突(contentprovider数据共享机制)

g、  安装目录不存在 调用install进行安装

h、  对pkgSetting进行设置并将pkgSetting添加到mPackages(Settings类中的成员)

i、  将Package添加到mPackages(PackageManagerService中)

j、 将(Package中的Provider、Service、Activity、Permission、Instrumentation分别添加到mProviders、mServices、mActivities、mSettings.mPermissionTrees或mSettings.mPermissions、mInstrumentation,

这样,PackageManagerService就基本上完成了他的任务,后面如果我们运行的过程中要安装apk,也会进行相类似的处理

android的PackageManagerService详解的更多相关文章

  1. android:ToolBar详解

    android:ToolBar详解(手把手教程) 泡在网上的日子 发表于 2014-11-18 12:49 第 124857 次阅读 ToolBar 42 来源 http://blog.mosil.b ...

  2. Android之canvas详解

    首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, y ...

  3. 【转】Android Canvas绘图详解(图文)

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...

  4. Android 核心分析 之八Android 启动过程详解

    Android 启动过程详解 Android从Linux系统启动有4个步骤: (1) init进程启动 (2) Native服务启动 (3) System Server,Android服务启动 (4) ...

  5. Android GLSurfaceView用法详解(二)

    输入如何处理       若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件.下面有个例子: java代码: package eoe.ClearTes ...

  6. Android编译过程详解(一)

    Android编译过程详解(一) 注:本文转载自Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359 ...

  7. android屏幕适配详解

    android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要 ...

  8. Android.mk文件详解(转)

    源:Android.mk文件详解 从对Makefile一无所知开始,折腾了一个多星期,终于对Android.mk有了一个全面些的了解.了解了标准的Makefile后,发现Android.mk其实是把真 ...

  9. Android Studio 插件开发详解四:填坑

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78265540 本文出自[赵彦军的博客] 在前面我介绍了插件开发的基本流程 [And ...

随机推荐

  1. consul怎么在windows下安装

    1.去官网下载:https://www.consul.io/downloads.html 2.解压: 3.设置环境变量:path添加 E:\programfiles\consul: 4.cmd启动: ...

  2. Why Helm? - 每天5分钟玩转 Docker 容器技术(160)

    本章我们将学习 Helm,Kubernetes 的包管理器. 每个成功的软件平台都有一个优秀的打包系统,比如 Debian.Ubuntu 的 apt,Redhat.Centos 的 yum.而 Hel ...

  3. EF实体的部分更新

    实现实体的部分更新假设实体InfoHotel如下: public class InfoHotel { public int Id{get;set;} public string Name{get;se ...

  4. python学习之路网络编程篇(第五篇)-续篇

    Python堡垒机实现之基础知识 一般的堡垒机必须要具备以下5个基本功能: 1.权限控制 2.执行命令 3.上传下载文件 4.远程登录 5.记录操作 权限控制 说明:根据不同的登录用户分配不同的可管理 ...

  5. SQL SERVER Management Studio

    1.​ 实验目的 ​ 熟悉SQL SERVER Management Studio的部分操作 ​ 数据SQL SERVER简化版和完整版数据库设计 2.​ 实验内容 2.1.​ 熟悉简化版SQL ...

  6. git清空某个文件的历史版本

    比如你要清空文件private.ini git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch priva ...

  7. SpringBatch的核心组件JobLauncher和JobRepository

    Spring Batch的框架包括启动批处理作业的组件和存储Job执行产生的元数据.因此只需掌握配置这个基础框架在批处理应用程序中即启动Jobs并存储Job元数据. 组件:Job Launcher和J ...

  8. Sencha EXTJS6的 Eclipse 插件安装指南

    Sencha EXTJS的 Eclipse 插件安装指南 (翻译:苏生米沿) 本文地址:http://blog.csdn.net/sushengmiyan/article/details/52566 ...

  9. 用Netty开发中间件:网络编程基础

    用Netty开发中间件:网络编程基础 <Netty权威指南>在网上的评价不是很高,尤其是第一版,第二版能稍好些?入手后快速翻看了大半本,不免还是想对<Netty权威指南(第二版)&g ...

  10. 深入Java虚拟机(2)——Java的平台无关性

    一.平台无关性的好处 Java技术在网络环境下非常有用,其中一个关键理由是,用Java创建的可执行二进制程序,能够不加改变地运行于多个平台. 这样的平台无关性随之带来许多的好处.这将极大地减轻系统管理 ...