Email:
[email protected]
Blog http://zcatt.blog.chinaunix.net
内容提要
Android如何寻找intent受体.以供备忘和参考。
声明
仅限学习交流,禁止商业用途。转载需注明出处。
版本记录
Date Ver Note
2011-04-27 0.1 Draft. zcatt, Beijing
PackageManagerService的方法大致可以分成这样几类,
1)从apk, xml中载入pacakge信息, 存储到内部成员变量中, 用于后面的查找. 关键的方法是scanPackageLI().
2)各种查询操作, 包括query Intent操作.
3)install package和delete package的操作. 关键的方法是installPackageLI().
4)其它操作, 包括permission, signature, freeStorage等等.
首先看看PacakgeManagerService用到的几个重要的支撑类, 然后罗列几个PackageManagerService的几个关键内部数据成员变量. 最后注记几个关键流程.
PackageManagerService用到了几个重要的支撑类:
PackageParser, 这个类主要用于解析apk, 分析其AndroidManifest.xml得到package的各种信息. 前已有注记文章,此不赘述. 特别的PackageParser.Package这个类用于容纳解析出的信息.
PackageManagerService.Settings, 用于容纳当前有效的package信息, 它是动态的. 例如, user id, shareUser, permission, signature以及origPackage(也就是mRenamedPackages)相关信息. 所谓的install package就包括从要安装的package中抽取信息更新PackageManagerService.Settings中的内容. 特别的, Settings针对shareUser和origPackage做了特别的关照. 另外, 为了加速启动速度, Settings的内容会写入到/data/system/packages.xml, packages-backup.xml, 和packages.list中, 下次启动时会直接载入.
Installer, 这个类协助安装过程, 更多的是将针对文件/路径的操作放到了c/cpp实现. 真正的工作是是由installd承担的, Installer只是通过named socket "installd"连接installd, 使用简单的cmd-respond协议指挥installd完成工作. 在其'install'命令中可以看到, 其实只是创建了/data/data/<pkgName>目录而已.
PackageManagerService中的几个关键成员变量:
- // (pkgName => Package), package is the one installed.
- final HashMap<String, PackageParser.Package> mPackages =
- new HashMap<String, PackageParser.Package>();
- // current package settings info, such as userid, origPackage
- // , shareUser, permission, signature, etc
- final Settings mSettings;
- // (system uid => permission), permissions read from /system/etc/permissions/<files> are stored here.
- // especially /system/etc/permissions/platform.xml
- final SparseArray<HashSet<String>> mSystemPermissions =
- new SparseArray<HashSet<String>>();
- //(pkgName => sharedLib), corresponding to <library> tag
- final HashMap<String, String> mSharedLibraries =
- new HashMap<String, String>();
- // All available activities, for resolving intent
- final ActivityIntentResolver mActivities =
- new ActivityIntentResolver();
- // All available receivers, for resolving intent
- final ActivityIntentResolver mReceivers =
- new ActivityIntentResolver();
- // All available services, for resolving intent
- final ServiceIntentResolver mServices =
- new ServiceIntentResolver();
几个关键流程,
初始化过程
--------------
PackageManagerService由SystemServer在创建ActivityManagerService后调用main创建, 是单实例的.
- Slog.i(TAG, "Power Manager");
- power = new PowerManagerService();
- ServiceManager.addService(Context.POWER_SERVICE, power);
- Slog.i(TAG, "Activity Manager");
- context = ActivityManagerService.main(factoryTest);
- Slog.i(TAG, "Telephony Registry");
- ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
- AttributeCache.init(context);
- Slog.i(TAG, "Package Manager");
- pm = PackageManagerService.main(context,
- factoryTest != SystemServer.FACTORY_TEST_OFF);
- ActivityManagerService.setSystemProcess();
- mContentResolver = context.getContentResolver();
在构造函数中, PackageManagerService会做这些工作,
1)启动自己的handlerThread, 生成自己的mHandler.
2)从/system/etc/permissions/的所有xml文件中, 尤其是platform.xml, 读入systemPermissions. 这些是系统默认的permission配置.
3)扫描/system/framework/, /system/app/, /data/app/, 和/data/app-private/下的apk文件, 收集package各种信息, 更新到内部成员变量中. 这些将在PackageManagerService执行各种功能时用到. 尤其是query intent.
更详尽的笔记,
PackageManagerService
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
readPermissions();
mRestoredSettings = mSettings.readLP();
--/system/framework/
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_NO_DEX);
--/system/app/
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
--Prune any system packages that no longer exist.
--clean up any incomplete package installations
--delete tmp files
--/data/app/
scanDirLI(mAppInstallDir, 0, scanMode);
--/data/app-private/
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode);
mSettings.writeLP();
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode)
PackageParser pp = new PackageParser(scanPath);
pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)
setApplicationInfoPaths(pkg, codePath, resPath);
scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
--set mAndroidApplication and mResolveActivity to'Android' package
--Check all shared libraries and map to their actual file path.
--check pkg.usesLibraries are contained in mSharedLibraries.
--fill in pkg.usesLibraryFiles according to pkg.usesLibraries and pkg.usesOptionalLibraries
--check pkg.reqFeatures in mAvailableFeatures
--if not in mSettings, create one ShareUserSettings and insert into mSettings.
--Check and note if we are renaming from an original package name
pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile, destResourceFile, pkg.applicationInfo.flags, true, false);
verifySignaturesLP(pkgSetting, pkg);
--Verify that this new package doesn't have any content providers that conflict with existing packages.
--get data dir. if not exists, install or create the data dir. if exists but uid not correct, reinstall.
--Perform shared library installation and dex validation and optimization, if this is not a system app.
--Request the ActivityManager to kill the process(only for existing packages)
mSettings.insertPackageSettingLP(pkgSetting, pkg); --Add the new setting to mSettings
mPackages.put(pkg.applicationInfo.packageName, pkg);
--set mProvidersByComponent and mProviders according to pkg.providers
--set mServices according to pkg.services
--set mReceivers according to pkg.receivers
--set mActivites according to pkg.activities
--set mPermissionGroups according to pkg.permissionGroups
--set mSettings.mPermissionTrees or mSettings.mPermissions according to pkg.permissions
--set mInstrumentation according to pkg.instrumentation
--set mProtectedBroadcasts according to pkg.protectedBroadcasts
install package过程
--------------
install package的入口是installPackage(). install package通常是个耗时的过程, 因此会使用到android的handler机制.
首先, 参数封装成INIT_COPY message, 发到handlerThread.
handlerThread收到message后, 将参数排队到mPendingInstalls中. 随后,MCS_BOUND流程将会处理这个队列, 执行安装.
MCS_BOUND的整个安装流程借助了几个InstallParams和InstallArgs完成其中的参数和安装结果的传递. 最终会调用processPendingInstall(), 进而调用到install过程的核心 installPackageLI().
installPackageLI()的复杂性很大程度上是考虑了1)新安装还是升级情况, 2)origPackage情况.