在前面分析Service和Broadcast的时候经常提到PackageManagerService,今天就系统的对他进行分析一下。
Android的包管理是典型的代理模式,也就是分为客户端和服务端的实现,下面来看看源码中的代码列表
客户端(本地端)在\platform\frameworks\base\core\java\android\content\pm路径下:
从这个图中可以看到ActivityInfo,ApplicationInfo,ComponentInfo以及等等一些info.java都是一些用来记录当前应用信息的数据结构类(这些数据基本都是从manifest文件中解析出来的),对应的aidl文件是为了使得这些数据结构可以在AIDL方式的跨进程通信方式中轻松传递。
还有一些数据结构在后面分析时用到了再详细阐述。
接下来的IPackageDataObserver、IPackageDeleteObserver、IPackageInstallObserver、IPackageMoveObserver和IPackageStatsObserver的aidl文件都是表示的一种跨进程回调机制,用来执行一系列的操作完成之后的回调操作。
注意一下这里有两个关键的文件IPackageManager.aidl和PackageManager.java,他们和下面要说的PackageManagerService一起是包管理机制的核心,分别代表了包管理对外提供的方法、本地客户端和远程服务端。
最后XmlSerializerAndParser.java定义了一个用于解析xml文件的接口。
还有服务端的实现:platform\frameworks\base\services\java\com\android\server\pm路径下:
这个包里面文件就少得多了,
BackgroundDexOptService.java主要用于classes文件的odex优化。
Installer是用来实现Package的install、dexopt和remove等操作的实体,它通过socket与底层installd交互实现基本功能。
PackageManagerService是应用包管理机制的核心实现类,里面包含了几乎所有的操作。
PackageSignatures主要用于解析当前应用的签名信息。
PreferredActivity和PreferredIntentResolver用于处理同一Intent多个应用可以接收时的默认启动项。
SELinuxMMAC类用于管理一些安全策略。
Settings是存储一些包管理过程中的状态,感觉应该设计为单例的,但是这个是在PackageManagerService中统一管理的也就一个对象并有与手机运行相同的生命周期。
SharedUserSetting是GrantedPermissions的子类它们是用来处理APP的共享用户id的,与PackageSignatures签名是息息相关的。
UserManagerService是IUserManager的Stub,看来也是一个跨进程的东西,它是在多用户的系统中用来管理用户及其各种信息的。
这两部分所涉及到的类都很多,分析源码也不能一个文件一个文件的分析,所以我们还是从几个主要的操作场景来切入,主要是APK的安装,升级,卸载,启用和禁用。然后再从框架上对其进行总结分析。
系统中用于安装应用有一个专门的APP叫PackageInstaller,在源码的这个位置android-4.4.3\platform\packages\apps\PackageInstaller。启动它是发送了一个广播,告诉系统我有意向要安装一个apk。
<activity android:name=".PackageInstallerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="package" />
</intent-filter>
</activity>
这是PackageInstaller的PackageInstallerActivity的Manifest注册信息,可以看到它可以接收Action为android.intent.action.VIEW和android.intent.action.INSTALL_PACKAGE的广播。然后就是由这个应用来执行应用的安装操作,这之前还会对所安装的apk的信息进行一个解析并展示给用户。
解析,这里第一次要提到PackageParser这个类,顾名思义就是包解析器,我们这里用到了parsePackage的接口,顺便我们会把这个类的其他重要接口也进行说明:(需要指出的是,这个类只是一个工具类,归根到底也只是一个XML文件解析而已,还没有涉及到包管理机制本身。)下面会贴一些系统的源码,注意一下我源码中的中文注释。
public Package parsePackage(File sourceFile, String destCodePath,
DisplayMetrics metrics, int flags, boolean trustedOverlay) {
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = sourceFile.getPath();
//这里省略了对是否是APK文件的判断
XmlResourceParser parser = null;
AssetManager assmgr = null;
Resources res = null;
boolean assetError = true;
try {
assmgr = new AssetManager();
int cookie = assmgr.addAssetPath(mArchiveSourcePath);
if (cookie != 0) {
res = new Resources(assmgr, metrics, null);
assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
//这里是重点,对一个APK的解析内容主要来自于其AndroidManifest.xml的文件,所以这里创建了一个xml文件的解析器
parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
assetError = false;
} else {
Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
}
} catch (Exception e) {
Slog.w(TAG, "Unable to read AndroidManifest.xml of "
+ mArchiveSourcePath, e);
}
if (assetError) {
if (assmgr != null) assmgr.close();
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
return null;
}
String[] errorText = new String[1];
Package pkg = null;
Exception errorException = null;
try {
// XXXX todo: need to figure out correct configuration.
// 真正的工作从这里才开始,对xml文件所包含的信息进行全解析,包括Application、Activity等等信息
pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
}
if (pkg == null) {
// If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
// just means to skip this app so don't make a fuss about it.
if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) {
if (errorException != null) {
Slog.w(TAG, mArchiveSourcePath, errorException);
} else {
Slog.w(TAG, mArchiveSourcePath + " (at "
+ parser.getPositionDescription()
+ "): " + errorText[0]);
}
if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
}
}
parser.close();
assmgr.close();
return null;
}
//不要忘记在文件处理之后需要关闭一些资源
parser.close();
assmgr.close();
// Set code and resource paths
pkg.mPath = destCodePath;
pkg.mScanPath = mArchiveSourcePath;
//pkg.applicationInfo.sourceDir = destCodePath;
//pkg.applicationInfo.publicSourceDir = destRes;
pkg.mSignatures = null;
return pkg;
}
来看看真正的解析方法吧,这个方法很长,可以细看这个方法能加深对AndroidManifest.xml文件的理解。
private Package parsePackage(
Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
String[] outError) throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
mParseActivityArgs = null;
mParseServiceArgs = null;
mParseProviderArgs = null;
//解析包名
String pkgName = parsePackageName(parser, attrs, flags, outError);
if (pkgName == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
int type;
if (mOnlyCoreApps) {
boolean core = attrs.getAttributeBooleanValue(null, "coreApp", false);
if (!core) {
mParseError = PackageManager.INSTALL_SUCCEEDED;
return null;
}
}
final Package pkg = new Package(pkgName);
boolean foundApp = false;
//下面是解析版本以及共享ID等信息
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
<span style="color:#FF0000;">//检测共享ID的合法性</span>
String nameError = validateName(str, true);
if (nameError != null && !"android".equals(pkgName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
+ str + "\": " + nameError;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
return null;
}
pkg.mSharedUserId = str.intern();
pkg.mSharedUserLabel = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
sa.recycle();
//检测APK指定安装位置,主要是SD卡和内置
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
PARSE_DEFAULT_INSTALL_LOCATION);
pkg.applicationInfo.installLocation = pkg.installLocation;
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
}
/* Set the global "on SD card" flag */
if ((flags & PARSE_ON_SDCARD) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
int supportsNormalScreens = 1;
int supportsLargeScreens = 1;
int supportsXLargeScreens = 1;
int resizeable = 1;
int anyDensity = 1;
int outerDepth = parser.getDepth();
//进入xml文件各个标签的处理了
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
//对标签名进行判断,以此对各种标签进行解析,下面的内容可以细看
if (tagName.equals("application")) {
.................
} else if (tagName.equals("overlay")) {
.................
} else if (tagName.equals("keys")) {
if (!parseKeys(pkg, res, parser, attrs, outError)) {
return null;
}
} else if (tagName.equals("permission-group")) {
if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission")) {
if (parsePermission(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission-tree")) {
if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("uses-permission")) {
if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
return null;
}
} else if (tagName.equals("uses-configuration")) {
......................
} else if (tagName.equals("uses-feature")) {
......................
} else if (tagName.equals("uses-sdk")) {
......................
} else if (tagName.equals("supports-screens")) {
......................
} else if (tagName.equals("protected-broadcast")) {
......................
} else if (tagName.equals("instrumentation")) {
if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("original-package")) {
.....................
} else if (tagName.equals("adopt-permissions")) {
.....................
} else if (tagName.equals("uses-gl-texture")) {
// Just skip this tag
XmlUtils.skipCurrentTag(parser);
continue;
} else if (tagName.equals("compatible-screens")) {
// Just skip this tag
XmlUtils.skipCurrentTag(parser);
continue;
} else if (tagName.equals("supports-input")) {
XmlUtils.skipCurrentTag(parser);
continue;
} else if (tagName.equals("eat-comment")) {
// Just skip this tag
XmlUtils.skipCurrentTag(parser);
continue;
} else if (RIGID_PARSER) {
outError[0] = "Bad element under <manifest>: "
+ parser.getName();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
}
if (!foundApp && pkg.instrumentation.size() == 0) {
outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
}
<span style="color:#FF0000;">//这下面有一段对新增权限的兼容处理,包括最后对较低版本上的APK在18以上运行的问题</span>
final int NP = PackageParser.NEW_PERMISSIONS.length;
StringBuilder implicitPerms = null;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
break;
}
if (!pkg.requestedPermissions.contains(npi.name)) {
if (implicitPerms == null) {
implicitPerms = new StringBuilder(128);
implicitPerms.append(pkg.packageName);
implicitPerms.append(": compat added ");
} else {
implicitPerms.append(' ');
}
implicitPerms.append(npi.name);
pkg.requestedPermissions.add(npi.name);
pkg.requestedPermissionsRequired.add(Boolean.TRUE);
}
}
if (implicitPerms != null) {
Slog.i(TAG, implicitPerms.toString());
}
final int NS = PackageParser.SPLIT_PERMISSIONS.length;
for (int is=0; is<NS; is++) {
final PackageParser.SplitPermissionInfo spi
= PackageParser.SPLIT_PERMISSIONS[is];
if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
|| !pkg.requestedPermissions.contains(spi.rootPerm)) {
continue;
}
for (int in=0; in<spi.newPerms.length; in++) {
final String perm = spi.newPerms[in];
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
pkg.requestedPermissionsRequired.add(Boolean.TRUE);
}
}
}
if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
}
if (supportsNormalScreens != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
}
if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
}
if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
}
if (resizeable < 0 || (resizeable > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
}
if (anyDensity < 0 || (anyDensity > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
}
/*
* b/8528162: Ignore the <uses-permission android:required> attribute if
* targetSdkVersion < JELLY_BEAN_MR2. There are lots of apps in the wild
* which are improperly using this attribute, even though it never worked.
*/
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) {
for (int i = 0; i < pkg.requestedPermissionsRequired.size(); i++) {
pkg.requestedPermissionsRequired.set(i, Boolean.TRUE);
}
}
return pkg;
}
继续分析流程,解析了APK信息之后,就是安装操作,我们来看看InstallAppProgress这个类的initView方法
public void initView() {
setContentView(R.layout.op_progress);
int installFlags = 0;
PackageManager pm = getPackageManager();
try {
<span style="color:#FF0000;">//判断当前需要安装的apk信息是否已经存在,如果已经存在则设置当前flags中替换安装的属性</span>
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
}
final PackageUtil.AppSnippet as;
if ("package".equals(mPackageURI.getScheme())) {
as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo),
pm.getApplicationIcon(mAppInfo));
} else {
final File sourceFile = new File(mPackageURI.getPath());
as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile);
}
......................
PackageInstallObserver observer = new PackageInstallObserver();
if ("package".equals(mPackageURI.getScheme())) {
try {
pm.installExistingPackage(mAppInfo.packageName);
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_SUCCEEDED);
} catch (PackageManager.NameNotFoundException e) {
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_FAILED_INVALID_APK);
}
} else {
<span style="color:#FF0000;">//重点来了,这里就是安装方法。</span>
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);
}
}
这里通过getPackageManager()获取到的是PackageManager的一个直接子类ApplicationPackageManager。我们来看看它的installPackageWithVerificationAndEncryption()方法。
@Override
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
try {
mPM.installPackageWithVerificationAndEncryption(packageURI, observer, flags,
installerPackageName, verificationParams, encryptionParams);
} catch (RemoteException e) {
// Should never happen!
}
}
无处不在的跨进程来了,实际上它也是在调用远程服务PackageManagerService来完成的安装功能(这里还有一个跨进程的回调IPackageInstallObserver),这个方法名字中包含了两个关键字Verifivation和Encryption,也就是说它包含了验证和加密。
@Override
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
null);
final int uid = Binder.getCallingUid();
<span style="color:#FF0000;">//做当前Uid是否被限制的检查</span>
if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) {
try {
observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
} catch (RemoteException re) {
}
return;
}
UserHandle user;
if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(UserHandle.getUserId(uid));
}
final int filteredFlags;
if (uid == Process.SHELL_UID || uid == 0) {
if (DEBUG_INSTALL) {
Slog.v(TAG, "Install from ADB");
}
filteredFlags = flags | PackageManager.INSTALL_FROM_ADB;
} else {
filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB;
}
verificationParams.setInstallerUid(uid);
final Message msg = mHandler.obtainMessage(INIT_COPY);
<span style="color:#FF0000;">//将所有信息组成一个installParams的参数传递到子线程中指导下一步的COPY工作</span>
msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
verificationParams, encryptionParams, user);
mHandler.sendMessage(msg);
}
这段代码很简单,告诉我们实际上安装APK对系统来说先是一个文件的拷贝工作,这里有一个mHandler,可以想象拷贝文件这么耗时的工作肯定是在子线程中进行的,有handler肯定还有一个HandlerThread,没错在PackageManagerService构造方法中就已经准备好了。几经周折最终是调用了InstallParams的handleStartCopy()方法:
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
final boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// Check if both bits are set.
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
final long lowThreshold;
final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
.getService(DeviceStorageMonitorService.SERVICE);
if (dsm == null) {
Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
lowThreshold = 0L;
} else {
lowThreshold = dsm.getMemoryLowThreshold();
}
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, mPackageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
final File packageFile;
//下面这一段代码主要是加密安装文件的,创建一个临时文件来实现加解密
if (encryptionParams != null || !"file".equals(mPackageURI.getScheme())) {
mTempPackage = createTempPackageFile(mDrmAppPrivateInstallDir);
if (mTempPackage != null) {
ParcelFileDescriptor out;
try {
out = ParcelFileDescriptor.open(mTempPackage,
ParcelFileDescriptor.MODE_READ_WRITE);
} catch (FileNotFoundException e) {
out = null;
Slog.e(TAG, "Failed to create temporary file for : " + mPackageURI);
}
// Make a temporary file for decryption.
ret = mContainerService
.copyResource(mPackageURI, encryptionParams, out);
IoUtils.closeQuietly(out);
packageFile = mTempPackage;
FileUtils.setPermissions(packageFile.getAbsolutePath(),
FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP
| FileUtils.S_IROTH,
-1, -1);
} else {
packageFile = null;
}
} else {
packageFile = new File(mPackageURI.getPath());
}
if (packageFile != null) {
// Remote call to find out default install location
final String packageFilePath = packageFile.getAbsolutePath();
pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath, flags,
lowThreshold);
<span style="color:#FF0000;"> /*
* If we have too little free space, try to free cache
* before giving up.
*/</span>
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
final long size = mContainerService.calculateInstalledSize(
packageFilePath, isForwardLocked());
if (mInstaller.freeCache(size + lowThreshold) >= 0) {
pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath,
flags, lowThreshold);
}
/*
* The cache free must have deleted the file we
* downloaded to install.
*
* TODO: fix the "freeCache" call to not delete
* the file we care about.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
}
} finally {
mContext.revokeUriPermission(mPackageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
<span style="color:#FF0000;">//下面所有的Failed字符串都是代表了一种安装时的错误。从pkgLite中解析出来的都是文件系统一类的错误,比如路径错误,空间不足等等。</span>
if (ret == PackageManager.INSTALL_SUCCEEDED) {
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
// Override with defaults if needed.
<span style="color:#FF0000;">// 设置安装的位置</span>
loc = installLocationPolicy(pkgLite, flags);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (!onSd && !onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
flags |= PackageManager.INSTALL_EXTERNAL;
flags &= ~PackageManager.INSTALL_INTERNAL;
} else {
// Make sure the flag for installing on external
// media is unset
flags |= PackageManager.INSTALL_INTERNAL;
flags &= ~PackageManager.INSTALL_EXTERNAL;
}
}
}
}
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
/*
* ADB installs appear as UserHandle.USER_ALL, and can only be performed by
* UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
*/
int userIdentifier = getUser().getIdentifier();
if (userIdentifier == UserHandle.USER_ALL
&& ((flags & PackageManager.INSTALL_FROM_ADB) != 0)) {
userIdentifier = UserHandle.USER_OWNER;
}
/*
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, userIdentifier);
// 以下分为两种情况,if中是需要验证的向外发送广播并接收结果然后到handler中去处理
// 我没有看到这个Intent.ACTION_PACKAGE_NEEDS_VERIFICATION这个广播的接收者就先不分析这一块了,有知道的可以告诉我,谢谢
// else就直接进行了文件的拷贝
if (requiredUid != -1 && isVerificationEnabled(flags)) {
final Intent verification = new Intent( Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.setDataAndType(getPackageUri(), PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
.......................
if (ret == PackageManager.INSTALL_SUCCEEDED && mRequiredVerifierPackage != null) {
/* * Send the intent to the required verification agent,
* but only start the verification timeout after the
* target BroadcastReceivers have run.
*/ verification.setComponent(requiredVerifierComponent);
mContext.sendOrderedBroadcastAsUser(verification, getUser(),
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg = mHandler .obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId; mHandler.sendMessageDelayed(msg, getVerificationTimeout());
}
}, null, 0, null, null);
/* * We don't want the copy to proceed until verification
* succeeds, so null out this field.
*/ mArgs = null;
}
} else {
/* * No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
*/ ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
紧接着应该是handleReturnCode()的时候了,文件拷贝完成之后才是对系统来说的安装过程,在这里需要将APK的所有信息采集注册和管理。调用的是processPendingInstall方法里面向mHandler中post了一个Runnable来异步执行installPackageLI:
private void installPackageLI(InstallArgs args,
boolean newInstall, PackageInstalledInfo res) {
int pFlags = args.flags;
String installerPackageName = args.installerPackageName;
File tmpPackageFile = new File(args.getCodePath());
boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
boolean replace = false;
int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
| (newInstall ? SCAN_NEW_INSTALL : 0);
// Result object to be returned
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Retrieve PackageSettings and parse package
<span style="color:#FF0000;">// 以下就是对当前所安装的APK信息进行解析</span>
int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
PackageParser pp = new PackageParser(tmpPackageFile.getPath());
pp.setSeparateProcesses(mSeparateProcesses);
final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
null, mMetrics, parseFlags);
if (pkg == null) {
res.returnCode = pp.getParseError();
return;
}
String pkgName = res.name = pkg.packageName;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
return;
}
}
<span style="color:#FF0000;">// 签名检查,这是Android安全性的重要组成部分,下面将着重讲解</span>
if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
res.returnCode = pp.getParseError();
return;
}
<span style="color:#FF0000;">// 下面是manifest摘要检查,判断之前验证的manifestDigest与当前解析的内存是否一致,这里对验证内容的过程有点没太明白,忘能人指点</span>
/* If the installer passed in a manifest digest, compare it now. */
if (args.manifestDigest != null) {
if (DEBUG_INSTALL) {
final String parsedManifest = pkg.manifestDigest == null ? "null"
: pkg.manifestDigest.toString();
Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
+ parsedManifest);
}
if (!args.manifestDigest.equals(pkg.manifestDigest)) {
res.returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
return;
}
} else if (DEBUG_INSTALL) {
final String parsedManifest = pkg.manifestDigest == null
? "null" : pkg.manifestDigest.toString();
Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
}
// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
<span style="color:#FF0000;">// Check if installing already existing package</span>
<span style="color:#FF0000;">// 流程是,如果是替换安装,有两种情况一种是包名有变化(看来替换安装包名是可以不一样的,也就是在AndroidManifest文件中申明original-package标签),
// 还有一种是包名一致的。</span>
if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.mRenamedPackages.get(pkgName);
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
+ oldName + " pkgName=" + pkgName);
} else if (mPackages.containsKey(pkgName)) {
// This package, under its official name, already exists
// on the device; we should replace it.
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
}
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
// 系统APK不允许安装到SD卡上
if (systemApp && onSd) {
// Disable updates to system apps on sdcard
Slog.w(TAG, "Cannot install updates to system apps on sdcard");
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
return;
}
//重命名
if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return;
}
// Set application objects path explicitly after the rename
setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
// 更新安装
replacePackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
} else {
// 安装新APK
installNewPackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
}
我们先来看看签名检查那一块,Android的签名机制属于安全机制的范畴,主要用于检验程序的来源,当然它也与系统的权限管理相关联。主要是两个方法:
public boolean collectCertificates(Package pkg, int flags) {
pkg.mSignatures = null;
WeakReference<byte[]> readBufferRef;
byte[] readBuffer = null;
synchronized (mSync) {
readBufferRef = mReadBuffer;
if (readBufferRef != null) {
mReadBuffer = null;
readBuffer = readBufferRef.get();
}
if (readBuffer == null) {
readBuffer = new byte[8192];
readBufferRef = new WeakReference<byte[]>(readBuffer);
}
}
try {
StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath);
Certificate[] certs = null;
if ((flags&PARSE_IS_SYSTEM) != 0) {
// If this package comes from the system image, then we
// can trust it... we'll just use the AndroidManifest.xml
// to retrieve its signatures, not validating all of the
// files.
// 针对系统预置APK的处理,只需要检查其Manifest文件即可
ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
certs = loadCertificates(jarFile, jarEntry, readBuffer);
if (certs == null) {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no certificates at entry "
+ jarEntry.getName() + "; ignoring!");
jarFile.close();
mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
return false;
}
if (DEBUG_JAR) {
Slog.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry
+ " certs=" + (certs != null ? certs.length : 0));
if (certs != null) {
final int N = certs.length;
for (int i=0; i<N; i++) {
Slog.i(TAG, " Public key: "
+ certs[i].getPublicKey().getEncoded()
+ " " + certs[i].getPublicKey());
}
}
}
} else {
Iterator<ZipEntry> entries = jarFile.iterator();
while (entries.hasNext()) {
final ZipEntry je = entries.next();
if (je.isDirectory()) continue;
final String name = je.getName();
if (name.startsWith("META-INF/"))
continue;
if (ANDROID_MANIFEST_FILENAME.equals(name)) {
pkg.manifestDigest =
ManifestDigest.fromInputStream(jarFile.getInputStream(je));
}
final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);
if (DEBUG_JAR) {
Slog.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName()
+ ": certs=" + certs + " ("
+ (certs != null ? certs.length : 0) + ")");
}
if (localCerts == null) {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no certificates at entry "
+ je.getName() + "; ignoring!");
jarFile.close();
mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
return false;
} else if (certs == null) {
certs = localCerts;
} else {
// Ensure all certificates match.
for (int i=0; i<certs.length; i++) {
boolean found = false;
for (int j=0; j<localCerts.length; j++) {
if (certs[i] != null &&
certs[i].equals(localCerts[j])) {
found = true;
break;
}
}
if (!found || certs.length != localCerts.length) {
Slog.e(TAG, "Package " + pkg.packageName
+ " has mismatched certificates at entry "
+ je.getName() + "; ignoring!");
jarFile.close();
mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return false;
}
}
}
}
}
jarFile.close();
synchronized (mSync) {
mReadBuffer = readBufferRef;
}
// 注意下面还有一个Android签名与数字证书的关系
if (certs != null && certs.length > 0) {
final int N = certs.length;
pkg.mSignatures = new Signature[certs.length];
for (int i=0; i<N; i++) {
pkg.mSignatures[i] = new Signature(
certs[i].getEncoded());
}
} else {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no certificates; ignoring!");
mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
return false;
}
// 这里有将所有的公钥保存到package的签名信息中,后面的验证主要也就是验证公钥
// Add the signing KeySet to the system
pkg.mSigningKeys = new HashSet<PublicKey>();
for (int i=0; i < certs.length; i++) {
pkg.mSigningKeys.add(certs[i].getPublicKey());
}
} catch (CertificateEncodingException e) {
Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
return false;
} catch (IOException e) {
Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
return false;
} catch (SecurityException e) {
Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
return false;
} catch (RuntimeException e) {
Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
return false;
}
return true;
}
这里的数字证书机制与JAVA中的完全一致,所以看到很多方法都是来源于JDK的标准方法。
private Certificate[] loadCertificates(StrictJarFile jarFile, ZipEntry je,
byte[] readBuffer) {
try {
// We must read the stream for the JarEntry to retrieve
// its certificates.
InputStream is = new BufferedInputStream(jarFile.getInputStream(je));
while (is.read(readBuffer, 0, readBuffer.length) != -1) {
// not using
}
is.close();
return je != null ? jarFile.getCertificates(je) : null;
} catch (IOException e) {
Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e);
}
r
其实到这里还只是将签名信息获取出来,还没有真正进行验证以及处理跟其相关的权限分配和用户组等过程,那些都在接下来的安装过程中。
关于Andoid签名机制这个博客有非常详细的阐述:http://blog.youkuaiyun.com/jiangwei0910410003/article/details/50443505,大家可以详细的了解。
说完这个发现本篇篇幅太长了,其他的后面再慢慢叙述吧。