今天我们来介绍下,同为Framework层的Packagemanager类(基于Android2.3.3源码分析),首先我们也先来看一下他的框架结构,之后再进行分析。
上图为Packagemanager框架图.‘
Pacakgemanager是一个抽象类,
源码:
public abstract class PackageManager { }
实现PackageManager抽象类的是ContextImpl类,在ContextImpl类中有一个静态子类ApplicationPackageManage继承自PackageManager.
代码:static final class ApplicationPackageManager extends PackageManager
所以我们在程序中通过getPackageManager获取的对象是ApplicationPackageManager。ApplicationPackageManager又通过对
IPackageManager的封装调用来实现的。
源码:
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
throw new NameNotFoundException(packageName);
}
private final IPackageManager mPM;
PackageManager框架中也利用了Proxy模式,即IPackageManager接口定义了所有PackageManager框架的操作,
IPackageManager.Stub.Proxy实现了接口IPackageManager,但并不真正实现这些方法,它只是一个代理类,
真正动作的执行为IPackageManager.Stub类的子类PackageManagerService,
这样我们就理顺了,PackageManager框架的流程结构。
下面来介绍下 PackageManager常用方法:
public abstract PackageManager getPackageManager()
功能:获得一个PackageManger对象
public abstract Drawable getApplicationIcon(String packageName)
参数: packageName 包名
功能:返回给定包名的图标,否则返回null
public abstract ApplicationInfo getApplicationInfo(String packageName, int flags)
参数:packagename 包名
flags 该ApplicationInfo是此flags标记,通常可以直接赋予常数0即可
功能:返回该ApplicationInfo对象
public abstract List<ApplicationInfo> getInstalledApplications(int flags)
参数:flag为一般为GET_UNINSTALLED_PACKAGES,那么此时会返回所有ApplicationInfo。我们可以对ApplicationInfo的flags过滤,得到我们需要的。
功能:返回给定条件的所有PackageInfo
public abstract List<ResolveInfo> queryIntentActivities(Intent intent, int flags)
参数:intent 查寻条件,Activity所配置的action和category
flags: MATCH_DEFAULT_ONLY:Category必须带有CATEGORY_DEFAULT的Activity,才匹配
GET_INTENT_FILTERS :匹配Intent条件即可
GET_RESOLVED_FILTER :匹配Intent条件即可
功能 :返回给定条件的所有ResolveInfo对象(本质上是Activity),集合对象
以上是一些PackageManager的方法,这里面还牵扯到PackageItemInfo类,AcitivityInfo类等,我们就不一一说了,有兴趣的同学可以自己看看。现在具体说一下最后一个方法,从而引出PackageManagerService,我们先来看看源码:
public List<ResolveInfo> queryIntentActivities(Intent intent,int flags) {
try {
return mPM.queryIntentActivities(//mPM是IPackageManager.Stub.Proxy对象
intent,intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags);
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
前面我们讲过了,这个方法的具体的执行操作其实是由PackageManagerService来完成的。PackageManagerService是一个很重要的工具类。PackageManagerService的启动流程分析:
PackageManagerService的构建:在system_process进程加载时,PackageManagerService就被创建了。在SystemServer.ServerThread.run中有如下一段代码:
pm = PackageManagerService.main(context,factoryTest != SystemServer.FACTORY_TEST_OFF);//启动PackageManagerService
它就是加载 PackageManagerService的,在
PackageManagerService中有一个静态方法:main()函数:
源代码:
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
ServiceManager.addService("package", m);
return m;
}
这个方法生成一个IPackageManager接口,也就是PackageManagerService。
在PackageManagerService初始化的时候,会建立 java 层的 installer 与 c 层的 installd 的 socket 联接,使得在上层的 install,remove,dexopt等功能最终由 installd 在底层实现。
源码: //建立 installer 与 installd 的 socket 联接
Installer installer = new Installer();
installer.ping() && Process.supportsProcesses();
installd 完成以下一些命令
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
{ "install", 3, do_install },
{ "dexopt", 3, do_dexopt },
{ "movedex", 2, do_move_dex },
{ "rmdex", 1, do_rm_dex },
{ "remove", 1, do_remove },
{ "rename", 2, do_rename },
{ "freecache", 1, do_free_cache },
{ "rmcache", 1, do_rm_cache },
{ "protect", 2, do_protect },
{ "getsize", 3, do_get_size },
{ "rmuserdata", 1, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
};
接下来会建立PackageHandler。 用 于 处 理 外 部 的 apk 安 装 请 求 消 息 , 如 adbinstall,packageinstaller 安装 apk 时会发送消息 。
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
处理的消息:
static final int SEND_PENDING_BROADCAST = 1;
static final int MCS_BOUND = 3;
static final int END_COPY = 4;
static final int INIT_COPY = 5;
static final int MCS_UNBIND = 6;
static final int START_CLEANING_PACKAGE = 7;
static final int FIND_INSTALL_LOC = 8;
static final int POST_INSTALL = 9;
static final int MCS_RECONNECT = 10;
static final int MCS_GIVE_UP = 11;
static final int UPDATED_MEDIA_STATUS = 12;
static final int WRITE_SETTINGS = 13;
再继续就是解析/system/etc/permission 下 xml 文件(framework/base/data/etc/),
源码:
// Read permissions from .../etc/permission directory.
File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
return;
}
if (!libraryDir.canRead()) {
Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
// Iterate over the files in the directory and scan .xml files
for (File f : libraryDir.listFiles()) {
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
continue;
}
if (!f.getPath().endsWith(".xml")) {
Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
if (!f.canRead()) {
Slog.w(TAG, "Permissions library file " + f + " cannot be read");
continue;
}
readPermissionsFromXml(f);
这里面包括platform.xml和系统支持的各种硬件模块的feature.主要工作:
(1) 建立底层 user ids 和 group ids 同上层 permissions 之间的映射;可以指定一个权限与几个组 ID 对应。当一个 APK 被授予这个权限时,它也同时属于这几个组。
(2) 给一些底层用户分配权限,如给 shell 授予各种 permission 权限;把一个权限赋予一个UID,当进程使用这个 UID 运行时,就具备了这个权限。
(3) library,系统增加的一些应用需要 link 的扩展 jar 库;
(4) feature, 系 统 每 增 加 一 个 硬 件 , 都 要 添 加 相 应 的 feature. 将 解 析 结 果mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures 等几个集合中供系统查询和权限配置使用。
接下来这行代码mSettings.readLP():
会判断/data/system/packages.xml 文件是否存在,如果不存在则返回 false,如果存在则进行解析,在系统第一次启动时 packages.xml 文件是不存在的,由 writeLP()创建该文件,文件里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通过apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。解析的过程即是按照 xml定义的标签,将对应的属性和值添加到全局列表中。
再继续就是检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt。
检查BootClassPath是否需要dexopt,如果需要先将文件添加到 libFiles 里,同时 进 行 dexopt
源码:
String bootClassPath = System.getProperty("java.boot.class.path");
if (bootClassPath != null) {
String[] paths = splitString(bootClassPath, ':');
for (int i=0; i<paths.length; i++) {
try {
if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
libFiles.add(paths[i]);
mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
didDexOpt = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Boot class path not found: " + paths[i]);
} catch (IOException e) {
Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
}
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
检查mSharedLibraries是否需要dexopt,如果需要先将文件添加到 libFiles 里,同时 进 行 dexopt
if (mSharedLibraries.size() > 0) {
Iterator<String> libs = mSharedLibraries.values().iterator();
while (libs.hasNext()) {
String lib = libs.next();
try {
if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
libFiles.add(lib);
mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
didDexOpt = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
Slog.w(TAG, "Exception reading library: " + lib, e);
}
}
}
对 framework-res.apk 不进行 dexopt 直接添加到 libFiles
libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
再继续启动 AppDirObserver 线程监测/system/framework,/system/app,/data/app,/data/app-private 目录的事件,目录监听底层通过inotify 机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。
mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
mFrameworkInstallObserver.startWatching();
再继续就是对以上几个目录下的apk进行逐个解析:调用 scanDirLI 解析,该函数是包管理服务的重要函数。
scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();
if (files == null) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (false) {
Log.d(TAG, "Scanning app dir " + dir);
}
int i;
for (i=0; i<files.length; i++) {
File file = new File(dir, files[i]);
if (!isPackageFilename(files[i])) {
// Ignore entries which are not apk's
continue;
}
PackageParser.Package pkg = scanPackageLI(file,
flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
// Don't mess around with apps in system partition.
if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
// Delete the apk
Slog.w(TAG, "Cleaning up failed install of " + file);
file.delete();
}
}
}
//对于不存在的 system apk 调用以下函数删除掉
Iterator psit = mSettings.mPackages.values().iterator();
PackageSetting ps = psit.next();
if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
&&!mPackages.containsKey(ps.name)
&& !mSettings.mDisabledSysPackages.containsKey(ps.name))
{
psit.remove();
mInstaller.remove(ps.name);
}
最后是解析完以上目录下的 apk 后,更新应用的权限 。
updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
mSettings.writeLP(); 会 生 成 packages.xml 和 packages.list 文 件 ,packages.list 的 数 据 格 式 是 :pkgName,userId,debugFlag,dataPath(包的数据路径),packages.xml 保存了每个已经安 装 apk 的详尽的信息 。
以上就是PackageManagerService从系统启动时所做的全部工作,下面再给大家贴一张整体流程的图: