您的位置:首页 > 移动开发 > Android开发

Android6.0 PackageManagerService(PMS)-安装

2017-08-21 16:58 567 查看
目录见上↑↑↑,整个安装过程可分为三步:

    1.权限检查

    2.复制文件

    3.装载应用

1.权限检查

调用installPackageAsUser函数

public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);

final int callingUid = Binder.getCallingUid();// 利用binder机制,获取安装发起进程的uid
//检查权限 该函数主要是检查进程是否有权限安装 展开见1.1
enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");

//检查当前用户是否具备安装app的权限
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
try {
if (observer != null) {
observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
}
} catch (RemoteException re) {
}
return;
}

//如果是发起端进程是shell或者root,那么添加flags:PackageManager.INSTALL_FROM_ADB
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
installFlags |= PackageManager.INSTALL_FROM_ADB;

} else {
// 从flags中去掉INSTALL_FROM_ADB和INSTALL_ALL_USERS
installFlags &= ~PackageManager.INSTALL_FROM_ADB;
installFlags &= ~PackageManager.INSTALL_ALL_USERS;
}

UserHandle user;//创建一个当前用户的handle
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}

// Only system components can circumvent runtime permissions when installing.
// Android 6.0 当权限属于运行时权限时,需要弹出框,让用户授权,对于system app,应该取消运行时权限弹框授权,而是直接授权。
// 那么就要在system app中加入INSTALL_GRANT_RUNTIME_PERMISSIONS;安装第三方app,当然没有INSTALL_GRANT_RUNTIME_PERMISSIONS了
if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
&& mContext.checkCallingOrSelfPermission(Manifest.permission
.INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
throw new SecurityException("You need the "
+ "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}

verificationParams.setInstallerUid(callingUid);

final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);//后续判断APK安装到哪里时,会用到

//构造InstallParams,注意packageAbiOverride为null,然后利用Android中的Handler机制,发送给相关的线程进行安装。
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
null, verificationParams, user, packageAbiOverride, null);
mHandler.sendMessage(msg);
}

其主要流程如图所示:



1.1 enforceCrossUserPermission

installPackageAsUser方法的前部调用了enforceCrossUserPermission,代码如下:

void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission,
boolean checkShell, String message) {
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
//当前userid和发起者进程所属的userid一致,那么OK,直接返回
// 我们现在就属于这种情况
if (userId == UserHandle.getUserId(callingUid)) return;

//不一致,那就要看是不是SYSTEM进程了,依旧不是,那么执行下逻辑,抛异常
if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
if (requireFullPermission) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
} else {
try {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
} catch (SecurityException se) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, message);
}
}
}
}


2.复制文件

权限检查中,installPackageAsUser方法尾部会发送一个INIT_COPY消息,接着会使用doHandleMessage方法处理收到的消息:

2.1 INIT_COPY

void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;//取出InstallParams
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// If a bind was already initiated we dont really need to do anything.
// The pending install will be processed later on.
if (!mBound) {
// If this is the only one pending we might have to bind to the service again.
// 将绑定DefaultContainerService服务
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();//连接服务失败
return;
} else {
// Once we bind to the service, the first pending request will be processed.
// 连接成功,把安装信息保存到mPendingInstalls中,等待收到连接的返回消息后,再继续安装
mPendingInstalls.add(idx, params);
}
} else {
// 加入安装信息
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
if (idx == 0) {
//如果mPendingInstalls中只有一项,那么立即发送MCS_BOUND消息
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
...
case 巴拉巴拉
}
}


INIT_COPY消息的处理中将绑定DefaultContainerService,因为这是一个异步的过程,要等待的绑定的结果通过onServiceConnected()返回,所以这里就将安装的参数信息放到了mPendingInstalls列表中。

如果这个Service之前就绑定好了,现在就不要再次绑定了,安装信息同样要放到mPendingInstalls中。

如果有多个安装请求同时到达,就可以通过mPendingInstalls列表对它们进行排队。

如果列表中只有一项,说明没有更多的安装请求,因此这种情况下,需要立即发出MCS_BOUND消息,进入下一步的处理。(应该有个INIT_COPY的流程图 简书那个)

2.1.1 connectToService

private boolean connectToService() {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" + " DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
if (mContext.bindServiceAsUser(service, mDefContainerConn,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}

绑定成功后在onServiceConnected中将一个IBinder转换成了一个IMediaContainerService。这个就是在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建的一个远程代理对象。以后PMS务通过该代理对象访问DefaultContainerService服务。

2.2 MCS_BOUND

case MCS_BOUND:  {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {//如果刚才绑定的DefaultContainerService失败
if (!mBound) {
// Something seriously wrong since we are not bound and we are not waiting for connection. Bail out.
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
// 连接失败,通过参数中的毁掉接口,通知调用者出错了
params.serviceError();
}
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
if (params.startCopy()) {//==============执行拷贝操作2.3
// We are done...  look for more work or to go idle.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Checking for more work or unbind...");
// Delete pending install
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);//工作完成后,删除第一项
}
if (mPendingInstalls.size() == 0) {
if (mBound) {//安装请求都处理完了
if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid continual thrashing.
// 如果没有安装信息了,则发送延时10秒的MCS_UNBIND消息
sendMessageDelayed(ubmsg, 10000);
}
} else {
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing of next pending install.
// 如果还有安装信息,则继续发送MCS_BOUND消息
if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting MCS_BOUND for next work");
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}

MCS_BOUND消息的处理过程:调用InstallParams类的startCopy()方法来执行拷贝操作。只要mPendingInstalls中还有安装信息,就会重复发送MCS_BOUND消息,直到所有的应用都安装完毕,然后在发送一个延时10秒的MCS_UNBIND消息。(这块再来个流程图看的明显一些)

2.2.1 MCS_UNBOUND

case MCS_UNBIND: {
// If there is no actual work left, then time to unbind.
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");

if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
if (mBound) {
if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");

disconnectService();
}
} else if (mPendingInstalls.size() > 0) {
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing of next pending install.
mHandler.sendEmptyMessage(MCS_BOUND);
}
break;
}

MCS_UNBIND消息的处理过程:当mPendingInstalls中没有安装信息的时候,就调用disconnectService方法断开与DefaultContainerService的连接;如果发现还有安装信息,则继续发送MCS_BOUND消息。

2.3 拷贝方法startCopy

final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

if (++mRetries > MAX_RETRIES) {// MAX_RETRIES为4
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
return false;
} else {
handleStartCopy();//展开2.3.1
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode();//会尝试重新绑定 展开,详见3
return res;
}

startCopy()方法通过调用其子类InstallParams的handleStartCopy()来完成拷贝操作。startCopy主要工作是进行错误处理,当捕获到handleStartCopy跑出的异常时,startCopy将发送MCS_RECONNECT消息。在对MCS_RECONNECT消息的处理中,将会重新绑定DefaultContainerService,如果绑定成功,那安装过程将会重新开始。startCopy也将会再次被调用,重试的次数记录在mRetries中
13834
,当累计重试超过4次时,安装将失败。如果安装失败,那么startCopy将会调用handleReturnCode()来继续处理。

2.3.1 handleStartCopy

public void handleStartCopy() throws RemoteException{
int ret = PackageManager.INSTALL_SUCCEEDED;

// If we're already staged, we've firmly committed to an install location
// 新安装时staged为false,前面在创建origin时,传入的false
// final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
} else if (origin.cid != null) {
installFlags |= PackageManager.INSTALL_EXTERNAL;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}

// 检查安装到哪里,SD卡还是内部
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;

//精简版PackageInfo
PackageInfoLite pkgLite = null;

// 如果同时设置了安装在内部存储中和外部SD中,则报错
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 {
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride);

//检查存储空间是否够安装该app,不够的话,执行如下分支
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
final StorageManager storage = StorageManager.from(mContext);
final long lowThreshold = storage.getStorageLowBytes(Environment.getDataDirectory());

final long sizeBytes = mContainerService.calculateInstalledSize(
origin.resolvedPath, isForwardLocked(), packageAbiOverride);

//尝试释放一些cache空间
if (mInstaller.freeCache(null, sizeBytes + lowThreshold) >= 0) {
//然后重新获取PackageInfoLite
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
installFlags, packageAbiOverride);
}

/*
* 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;
}
}
}

if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果上面这些步骤没报错的话,再判断pkgLite的信息
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 == PackageHehandleStartCopylper.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.
loc = installLocationPolicy(pkgLite);
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.
installFlags |= PackageManager.INSTALL_EXTERNAL;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
}
}
}
}

// 其中abiOverride为null,创建一个安装参数对象
final InstallArgs args = createInstallArgs(this);//=====2.3.1.1展开
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
&& ((installFlags & 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 (!origin.existing && requiredUid != -1
&& isVerificationEnabled(userIdentifier, installFlags)) {
//此处是进行校验,一大段代码
..................................
} 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;
}

handleStartCopy()方法会判断该app应该安装到哪里,如果安装空间不足的话,会尝试在清理一些cache空间后,再次尝试安装。该方法中很多代码是在将一些信息通过发送Intent android.intent.action.PACKAGE_NEEDS_VERIFICATION 给系统中所有接收该Intent进行处理。如果不需要校验的话,就直接调用InstallArgs的copyApk()方法。主要流程如图所示:



2.3.1.1 createInstallArgs


private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
// 移动app
return new MoveInstallArgs(params);
} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
// 安装在SD
return new AsecInstallArgs(params);
} else {
// 安装在内部存储
return new FileInstallArgs(params);
}
}

此处讨论安装在内部存储的,所以创建的就是FileInstallArgs了,那么调用的copyApk,也是FileInstallArgs的了。
copyApk主要是对apk内容进行拷贝,FileInstallArgs.copyApk的数据流如下:

创建data/app下的目录并修改权限为755

拷贝base.apk(DefaultContainerService.java里的copypackage函数,里用copyfile函数 构建输入输出流,调用Stream的方法进行拷贝)

拷贝so文件



3. 装载应用

在前面的处理MCS_BOUND时调用的HandlerParams的startCopy方法(2.3小节)中当复制完文件之后,会调用InstallParams的handleReturnCode方法。

3.1 handleReturnCode:

void handleReturnCode() {
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {//向mHandler发一个Runnable对象,异步
public void run() {
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
res.returnCode = currentStatus;
res.uid = -1;
res.pkg = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
//欲安装阶段,主要是检查安装包的状态和安装环境,如果有问题就清理拷贝文件
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
installPackageLI(args, res);//安装阶段, 展开详见3.2
}
// 安装失败时,删除/data/app/包名中的内容
args.doPostInstall(res.returnCode, res.uid);
}
.....................................
// 用InstallArgs和PackageInstalledInfo构造一个PostInstallData对象,然后存放在mRunningInstalls里面
// 这样之后通过mRunningInstalls这个SparseArray查询就行
// 如果安装成功&需要备份,则调用BackupManagerService来完成备份,并设置doRestore为false
 .....................................
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);//展开详见3.3
mHandler.sendMessage(msg);
}
}
});
}

processPendingInstall()方法中post了一个消息,这样安装过程将以异步的方式继续执行。在post消息中,首先是调用installPackageLI()来装载应用,接下来的一大段代码是在执行设备备份操作,备份是通过BackupManagerService来完成的,暂不分析。备份完成之后,通过发送POST_INSTALL消息继续处理。

3.2 installPackageLI[重要]

分析在代码注释中

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
//此段做了一些初始化值的工作
final int installFlags = args.installFlags;//记录了app需要安装到哪里
final String installerPackageName = args.installerPackageName;// 安装程序的包名
final String volumeUuid = args.volumeUuid;// 与sd卡安装有关,一般为null
final File tmpPackageFile = new File(args.getCodePath());// 前面copyApk中的临时阶段性文件夹/data/app/vmdl<安装回话id>.tmp/这个目录了
final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);// 没有设定INSTALL_FORWARD_LOCK
final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)// 是否安装到外部存储
|| (args.volumeUuid != null));
boolean replace = false;// 初始化替换flag为假
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;// 设置浏览参数
if (args.move != null) {// 我们不是移动app,所以为null,不走这块代码
// moving a complete application; perfom an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
}
// Result object to be returned
res.returnCode = PackageManager.INSTALL_SUCCEEDED;

//此段解析APK,也就是解析AndroidMainifest.xml文件,将结果记录在PackageParser.Package中
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Retrieve PackageSettings and parse package
// 设置解析apk的flags
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();// 创建一个解析器
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);// 获得屏幕参数

final PackageParser.Package pkg;
try {
// 开始解析apk,传入tmpPackageFile为一个文件夹
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
}

// Mark that we have an install time CPU ABI override.
pkg.cpuAbiOverride = args.abiOverride;

String pkgName = res.name = pkg.packageName;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
return;
}
}
//此段搜集apk的签名信息,这块具体实现 待看.有两篇blog
try {
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
}
// 如果安装程序此前传入了一个清单文件,那么将解析到的清单文件与传入的进行对比。
//安装器的确传入了一个清单,PackageInstallerActivity中也解析了apk,那时记录了这个清单,并一并传入到这里了。
//这里又做了一步判断,判断两者是同一个apk.
/* 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.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest 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) {
// // 如果安装已经存在的应用的时候,PackageInstaller应用安装器会在会在installFlags中设置INSTALL_REPLACE_EXISTING
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// 看看要替换的apk的包名是否存在原始包名
// 当app升级导致前后包名不一致的时候,需要记录仍然是原始包名,
// 所以这里要先检查要覆盖的app是否是这样的情况,是的话设置包名为旧的包名
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);
}

// Prevent apps opting out from runtime permissions
// 当一个app按照6.0来编译的话,需要按照6.0的规则来解析app的权限。
if (replace) {
PackageParser.Package oldPackage = mPackages.get(pkgName);
final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
"Package " + pkg.packageName + " new target SDK " + newTargetSdk
+ " doesn't support runtime permissions but the old"
+ " target SDK " + oldTargetSdk + " does.");
return;
}
}
}
createDataDirsLI方法中调用mInstaller.install安装---->例如mActivities.addActivity(..) 把四大组件信息注册到PMS内部
PackageSetting ps = mSettings.mPackages.get(pkgName);
// 如果ps不为null,同样说明,已经存在一个同包名的程序被安装,也就是还是处理覆盖安装的情况
// 这里主要是验证包名的签名,不一致的话,是不能覆盖安装的,另外版本号也不能比安装的低,否则也不能安装
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
if (!checkUpgradeKeySetLP(ps, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
return;
}
} else {
try {
//ps是已有的. pkg是新安装的. 检查签名
// 该函数分两步:
// 如果有老版本的签名 则检查老版本的签名和新安装包的签名是否一致
// 如果有共享用户的签名,则检查共享用户的签名与新安装包的签名是否一致。
// 每一步都是三重机制:判断两个ArraySet是否相同->是否因为版本问题->恢复下证书(担心因为有变动)再试着比对一次
 verifySignaturesLP(ps, pkg);
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
}
}

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);
}

// Check whether the newly-scanned package wants to define an already-defined perm
// 此段 检查apk中定义的权限是否已被其他应用定义过,如果重定义的是系统应用定义的权限,那么忽略本app定义的这个权限;如果重定义的是非系统应用的权限,则本次安装失败。
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
if (bp != null) {
// If the defining package is signed with our cert, it's okay.  This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
if (bp.sourcePackage.equals(pkg.packageName)
&& (bp.packageSetting instanceof PackageSetting)
&& (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
scanFlags))) {
sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
} else {
sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
if (!bp.sourcePackage.equals("android")) {
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ pkg.packageName + " attempting to redeclare permission "
+ perm.info.name + " already owned by " + bp.sourcePackage);
res.origPermission = perm.info.name;
res.origPackage = bp.sourcePackage;
return;
} else {
Slog.w(TAG, "Package " + pkg.packageName
+ " attempting to redeclare system permission "
+ perm.info.name + "; ignoring new declaration");
pkg.permissions.remove(i);
}
} else if (!"android".equals(pkg.packageName)) {
// Prevent apps to change protection level to dangerous from any other
// type as this would allow a privilege escalation where an app adds a
// normal/signature permission in other app's group and later redefines
// it as dangerous leading to the group auto-grant.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
if (bp != null && !bp.isRuntime()) {
Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
perm.info.protectionLevel = bp.protectionLevel;
}
}
}
}
}

}

//此段 当一个app是系统应用,但又希望安装在外部存储,那么就报错。
if (systemApp && onExternal) {
// Disable updates to system apps on sdcard
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
}

// 我们不是在移动app,所以不走这个分支,走else if分支
if (args.move != null) {
// We did an in-place move, so dex is ready to roll
scanFlags |= SCAN_NO_DEX;
scanFlags |= SCAN_MOVE;

synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps == null) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Missing settings for moved package " + pkgName);
}

// We moved the entire application as-is, so bring over the
// previously derived ABI information.
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}

} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
// 设置SCAN_NO_DEX,这样在这个阶段就不会执行dexopt
scanFlags |= SCAN_NO_DEX;

try {//apk包里lib目录下有.so文件的,可以通过.so文件的ABI来确定app的primaryCpuAbi的值
derivePackageAbi(pkg, new File(pkg.codePath), args.abiOverride,
true /* extract libs */);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
return;
}

// Run dexopt before old package gets removed, to minimize time when app is unavailable
int result = mPackageDexOptimizer
.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
false /* defer */, false /* inclDependencies */);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
return;
}
}cc

//重命名 将/data/app/vmdl<安装会话id>.tmp重命名为/data/app/包名-suffix,suffix为1,2...同时更新pkg中的受影响的字段。
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}

startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);

if (replace) {// 如果是覆盖安装,则走这里
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, volumeUuid, res);
} else {// 初次安装,走这里
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
}


执行完installPackageLI之后,返回processPendingInstall方法中。

3.3 发送POST_INSTALL消息并处理

case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
//Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); 所以msg.arg1是token
PostInstallData data = mRunningInstalls.get(msg.arg1);
//安装完毕,在"正在安装列表"中删除该项
mRunningInstalls.delete(msg.arg1);
boolean deleteOld = false;

if (data != null) {
InstallArgs args = data.args;
PackageInstalledInfo res = data.res;

//如果安装成功
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
final String packageName = res.pkg.applicationInfo.packageName;
//如果res.removedInfo.removedPackage != null 即如果是更新, 还会发送"ACTION_PACKAGE_REMOVED"广播
res.removedInfo.sendBroadcast(false, true, false);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);

// Now that we successfully installed the package, grant runtime
// permissions if requested before broadcasting the install.
if ((args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {
grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),
args.installGrantPermissions);
}

// Determine the set of users who are adding this
// package for the first time vs. those who are seeing
// an update.
int[] firstUsers;
int[] updateUsers = new int[0];
if (res.origUsers == null || res.origUsers.length == 0) {
firstUsers = res.newUsers;
} else {
firstUsers = new int[0];
for (int i=0; i<res.newUsers.length; i++) {
int user = res.newUsers[i];
boolean isNew = true;
for (int j=0; j<res.origUsers.length; j++) {
if (res.origUsers[j] == user) {
isNew = false;
break;
}
}
if (isNew) {
int[] newFirst = new int[firstUsers.length+1];
System.arraycopy(firstUsers, 0, newFirst, 0,
firstUsers.length);
newFirst[firstUsers.length] = user;
firstUsers = newFirst;
} else {
int[] newUpdate = new int[updateUsers.length+1];
System.arraycopy(updateUsers, 0, newUpdate, 0,
updateUsers.length);
newUpdate[updateUsers.length] = user;
updateUsers = newUpdate;
}
}
}

//上述是判断哪些用户是首次安装,哪些用户是更新安装
//发送一个ACTION_PACKAGE_ADDED广播(对首次安装的用户)
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, null, null, firstUsers);
final boolean update = res.removedInfo.removedPackage != null;
//如果是更新,extra字段添加一下值
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
//发送一个ACTION_PACKAGE_ADDED广播(对更新的用户)
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, null, null, updateUsers);
//如果是更新,发送ACTION_PACKAGE_REPLACED和ACTION_MY_PACKAGE_REPLACED广播
//sendPackageBroadcast的第四个参数是targetPkg
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, null, null, updateUsers);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null, null, packageName, null, updateUsers);

// treat asec-hosted packages like removable media on upgrade
//处理安装在SD卡的
if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg
+ " is ASEC-hosted -> AVAILABLE");
}
int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
ArrayList<String> pkgList = new ArrayList<String>(1);
pkgList.add(packageName);
//发送app->SD的资源更改广播
sendResourcesChangedBroadcast(true, true,
pkgList,uidArray, null);
}
}
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
deleteOld = true;
}

// If this app is a browser and it's newly-installed for some
// users, clear any default-browser state in those users
//如果是首次安装浏览器APP,则重置浏览器设置
if (firstUsers.length > 0) {
// the app's nature doesn't depend on the user, so we can just
// check its browser nature in any user and generalize.
if (packageIsBrowser(packageName, firstUsers[0])) {
synchronized (mPackages) {
for (int userId : firstUsers) {
mSettings.setDefaultBrowserPackageNameLPw(null, userId);
}
}
}
}
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
}
// Force a gc to clear up things
//GC操作
Runtime.getRuntime().gc();
// We delete after a gc for applications  on sdcard.
if (deleteOld) {
synchronized (mInstallLock) {
res.removedInfo.args.doPostDeleteLI(true);
}
}
//回调args.observer.packageInstalled方法。
//告诉PackageInstaller安装结果,从而实现了安装回调到UI层。
if (args.observer != null) {
try {
Bundle extras = extrasForInstallResult(res);
args.observer.onPackageInstalled(res.name, res.returnCode,
res.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
} else {
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
} break;

该消息的处理主要就是在发送广播(很多个),应用安装完成之后要通知系统中的其他应用开始处理,安装到此结束~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: