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. 利用create-react-app结合react-redux、react-router4构建单页应用

    1.创建项目: a.全局安装create-react-app: npm  install  create-react-app  -g b.执行create-react-app  my-projectN ...

  2. ubuntu15.10 安装 virtualbox5.0

    首先安装依赖包.ubuntu15.01安装的时候会出现这个错误: virtualbox-); however: Package libvpx1 is not installed 而且sudo apt- ...

  3. 检测linux vps是xen openvz还是kvm的方法

    很多时候不知道自己买的vps是那种虚拟化技术,怕给商家忽悠了,下面给大家介绍下怎么简单的判断自己vps的虚拟化技术. 1.通过系统上的相关目录或文件判断 ll /proc/   ps: /proc目录 ...

  4. 守护态运行Docker容器

    更多的时候,需要让 Docker 容器在后台以守护态(Daemonized)形式运行.此时,可以通过添加 -d 参数来实现. 例如下面的命令会在后台运行容器. $ sudo docker run -d ...

  5. Windows下Java调用BAT批处理不弹出cmd窗口

    常规Windows下Java调用BAT方式肯定会弹出cmd窗口 Runtime.getRuntime().exec("cmd.exe /C start D:\\test.bat") ...

  6. Dynamics CRM2016 Update or Create parentcustomerid in Contact using web api

    联系人实体中有个特殊的字段parentcustomerid 在通过web api创建或更新记录时,如果在给这个字段赋值时当做查找字段对待的话,那你就会遇到问题了,报错信息如下 正确的赋值方式如下

  7. ROS机器人程序设计(原书第2版)补充资料 (捌) 第八章 导航功能包集入门 navigation

    ROS机器人程序设计(原书第2版)补充资料 (捌) 第八章 导航功能包集入门 navigation 书中,大部分出现hydro的地方,直接替换为indigo或jade或kinetic,即可在对应版本中 ...

  8. ViewPager实现滑屏切换页面及动画效果(仿优酷客户端)

     找了许多实现该功能的例子,但效果都不很理想,于是自己结合网上的资源及自己的总结,整理了一下,发出来,供大家参考.这个是自己做的,仿优酷客户端的. 先看效果: ****************** ...

  9. Android中Snackbar的介绍以及使用

    Android中Snackbar的介绍以及使用 介绍 Snackbar可以说是Toast的升级版,不仅有显示信息的功能,还可以添加一个Action,实现点击功能,可以右滑删除. 效果图 Snackba ...

  10. SQLite 运算符(http://www.w3cschool.cc/sqlite/sqlite-operators.html)

    SQLite 运算符 SQLite 运算符是什么? 运算符是一个保留字或字符,主要用于 SQLite 语句的 WHERE 子句中执行操作,如比较和算术运算. 运算符用于指定 SQLite 语句中的条件 ...