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中
service installd /system/bin/installd 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中的部分
....... <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" > <group gid="cache" /> </permission> <!-- RW permissions to any system resources owned by group 'diag'. This is for carrier and manufacture diagnostics tools that must be installable from the framework. Be careful. --> <permission name="android.permission.DIAGNOSTIC" > <group gid="input" /> <group gid="diag" /> </permission> ...... <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" /> <assign-permission name="android.permission.SEND_SMS" uid="shell" /> <assign-permission name="android.permission.CALL_PHONE" uid="shell" /> <assign-permission name="android.permission.READ_CONTACTS" uid="shell" /> <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" /> <assign-permission name="android.permission.READ_CALENDAR" uid="shell" /> ....... <library name="android.test.runner" file="/system/framework/android.test.runner.jar" /> <library name="javax.obex" file="/system/framework/javax.obex.jar"/> <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<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <packages> <last-platform-version internal="9" external="0" /> <permission-trees /> <permissions> <item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1" /> <item name="android.permission.CLEAR_APP_USER_DATA" package="android" protection="2" /> <item name="android.permission.SHUTDOWN" package="android" protection="2" /> <item name="android.permission.BIND_INPUT_METHOD" package="android" protection="2" /> ................... <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"> <sigs count="1"> <cert index="0" /> </sigs> </package> .............. <shared-user name="android.uid.shared" userId="10000"> <sigs count="1"> <cert index="1" /> </sigs> <perms> <item name="android.permission.READ_SYNC_STATS" /> <item name="android.permission.USE_CREDENTIALS" /> <item name="android.permission.INTERNET" /> <item name="android.permission.SUBSCRIBED_FEEDS_READ" /> <item name="android.permission.READ_CONTACTS" /> <item name="android.permission.GET_ACCOUNTS" /> <item name="android.permission.WRITE_CONTACTS" /> <item name="android.permission.SUBSCRIBED_FEEDS_WRITE" /> </perms> </shared-user> ............... <preferred-activities> <item name="tv.ipanel.join.xjnt.homefinal/tv.ipanel.join.xjnt.home.XJNTHomeActivity" match="100000" set="2"> <set name="tv.ipanel.join.xjnt.home/.XJNTHomeActivity" /> <set name="tv.ipanel.join.xjnt.homefinal/tv.ipanel.join.xjnt.home.XJNTHomeActivity" /> <filter> <action name="android.intent.action.MAIN" /> <cat name="android.intent.category.HOME" /> <cat name="android.intent.category.DEFAULT" /> </filter> </item> </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中有一段静态程序块(当一个类需要在被载入时就执行一段程序,这样可以使用静态程序块)
static { s_observerThread = new ObserverThread(); s_observerThread.start(); }而它的run函数
public void run() { observe(m_fd); }
public ObserverThread() { super("FileObserver"); m_fd = init(); }
init比较简单,直接调用inotify_init返回一个句柄标识
static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd) { #ifdef HAVE_INOTIFY char event_buf[512]; struct inotify_event* event; while (1) { int event_pos = 0; int num_bytes = read(fd, event_buf, sizeof(event_buf)); if (num_bytes < (int)sizeof(*event)) { if (errno == EINTR) continue; LOGE("***** ERROR! android_os_fileobserver_observe() got a short event!"); return; } while (num_bytes >= (int)sizeof(*event)) { int event_size; event = (struct inotify_event *)(event_buf + event_pos); jstring path = NULL; if (event->len > 0) { path = env->NewStringUTF(event->name); } env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } if (path != NULL) { env->DeleteLocalRef(path); } event_size = sizeof(*event) + event->len; num_bytes -= event_size; event_pos += event_size; } } #endif // HAVE_INOTIFY }
public void onEvent(int wfd, int mask, String path) { // look up our observer, fixing up the map if necessary... FileObserver observer = null; synchronized (m_observers) { WeakReference weak = m_observers.get(wfd); if (weak != null) { // can happen with lots of events from a dead wfd observer = (FileObserver) weak.get(); if (observer == null) { m_observers.remove(wfd); } } } // ...then call out to the observer without the sync lock held if (observer != null) { try { observer.onEvent(mask, path); } catch (Throwable throwable) { Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable); } } }
public void onEvent(int event, String path) { String removedPackage = null; int removedUid = -1; String addedPackage = null; int addedUid = -1; synchronized (mInstallLock) { String fullPathStr = null; File fullPath = null; if (path != null) { fullPath = new File(mRootDir, path); fullPathStr = fullPath.getPath(); } if (Config.LOGV) Log.v( TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event)); if (!isPackageFilename(path)) { if (Config.LOGV) Log.v( TAG, "Ignoring change of non-package file: " + fullPathStr); return; } // Ignore packages that are being installed or // have just been installed. if (ignoreCodePath(fullPathStr)) { return; } PackageParser.Package p = null; synchronized (mPackages) { p = mAppDirs.get(fullPathStr); } if ((event&REMOVE_EVENTS) != 0) { if (p != null) { removePackageLI(p, true); removedPackage = p.applicationInfo.packageName; removedUid = p.applicationInfo.uid; } } if ((event&ADD_EVENTS) != 0) { if (p == null) { p = scanPackageLI(fullPath, (mIsRom ? PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR: 0) | PackageParser.PARSE_CHATTY | PackageParser.PARSE_MUST_BE_APK, SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME, System.currentTimeMillis()); if (p != null) { synchronized (mPackages) { updatePermissionsLP(p.packageName, p, p.permissions.size() > 0, false, false); } addedPackage = p.applicationInfo.packageName; addedUid = p.applicationInfo.uid; } } } synchronized (mPackages) { mSettings.writeLP(); } } if (removedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras, null); } }这里判断是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,也会进行相类似的处理