Android -- PackageManagerService APK安装流程简要分析
在Android系统下,我们一般会使用"adb install -r"命令来安装应用;此时应用会被安装到/data/app/下。这篇文章,我们就简要分析PackageManagerService安装apk的中间处理过程。
在进入PackageManager之前,我们先看下有关adb安装应用的内容。在android中,adbd以后台进程运行。当我们输入"adb install"命令时,/syste/core/adb/目录下commandline.cpp文件会被执行,其中adb_commandline()函数会接受该条指令,并进行处理,这里只看install命令的执行:
int adb_commandline(int argc, const char **argv) {
......
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
if (_use_legacy_install()) {
return install_app_legacy(transport_type, serial, argc, argv);
}
return install_app(transport_type, serial, argc, argv);
}
......
}
这里以legacy模式为例:
static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
static const char *const DATA_DEST = "/data/local/tmp/%s";//安装到data目录下时,会将apk先拷贝一份到该目录下
static const char *const SD_DEST = "/sdcard/tmp/%s";//安装到SD卡上时,会将apk先拷贝一份到/sdcard/tmp/目录下;一般带参数-s
const char* where = DATA_DEST;
int i;
struct stat sb;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
}
}
// Find last APK argument.
// All other arguments passed through verbatim.
int last_apk = -1;
for (i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
const char* dot = strrchr(file, '.');
if (dot && !strcasecmp(dot, ".apk")) {
if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
fprintf(stderr, "Invalid APK file: %s\n", file);
return EXIT_FAILURE;
}
last_apk = i;
break;
}
}
if (last_apk == -1) {
fprintf(stderr, "Missing APK file\n");
return EXIT_FAILURE;
}
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
std::string apk_dest = android::base::StringPrintf(
where, adb_basename(argv[last_apk]).c_str());
if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;//我们即将安装的apk文件也许会在客户机上,这里会先将该apk文件推送到系统的/data/local/tmp/目录下
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
result = pm_command(transport, serial, argc, argv);//执行pm脚本,进行安装
cleanup_apk:
delete_file(transport, serial, apk_dest);//安装过程结束后,会清掉事先拷贝的那一份apk
return result;
}
由于我们使用adb安装的apk有可能会在客户机上,所以这里会先将apk文件拷贝一份到系统的/data/local/tmp/目录下。然后,流程会去执行pm脚本进行安装操作。手机的端的adbd程序接收到客户机发送的shell pm命令后,会开启一个shell去执行pm脚本。pm脚本的内容如下:
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/pm.jar
exec app_process $base/bin com.android.commands.pm.Pm "$@"
该脚本在系统编译时会被打包成/system/bin/pm可执行程序,执行pm可执行程序其实就是执行这段脚本。我们知道,app_process在系统启动过程中会去启动Zygote系统进程;同时,它也可以被用来启动一些其他的普通进程,比如此时的pm。我们直接看启动pm时调用的main()函数,com.android.commands.pm.Pm::main():
public static void main(String[] args) {
int exitCode = 1;
try {
exitCode = new Pm().run(args);
} catch (Exception e) {
Log.e(TAG, "Error", e);
System.err.println("Error: " + e);
if (e instanceof RemoteException) {
System.err.println(PM_NOT_RUNNING_ERR);
}
}
System.exit(exitCode);
}
创建Pm实例并调用它的run()接口:
public int run(String[] args) throws RemoteException {
boolean validCommand = false;
if (args.length < 1) {
return showUsage();
}
mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));//IPackageManager实例,通过它可以调用到PackageManagerServcie中
if (mPm == null) {//IPackageManager实例为空,即返回
System.err.println(PM_NOT_RUNNING_ERR);
return 1;
}
mInstaller = mPm.getPackageInstaller();//IPackageInstaller实例,它会管理android中的应用安装状态
mArgs = args;
String op = args[0];
mNextArg = 1;
if ("list".equals(op)) {
return runList();
}
if ("path".equals(op)) {
return runPath();
}
if ("dump".equals(op)) {
return runDump();
}
if ("install".equals(op)) {//此处分析的是install命令,走这条分支
return runInstall();
}
......
}
因为我们传入的是install命令,所以执行runInstall()函数;至此,安装过程就即将进入PackageManagerService了。
同时,我们也可以调用PackageManager::installPackage()函数安装应用,这种方式的安装与adb install的安装流程再走进PackageManagerService之后,都是一致地。
PackageManager的家族类图结构如下所示:
PackageManager的功能由ApplicationPackageManager实现,ApplicationPackageManager内部持有一个指向PackageManagerService的mPM对象来传递函数调用。当我们调用PackageManager::installPackage()时,实际调用调用ApplicationPackageManager中的实现函数:
@Override
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName) {
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, mContext.getUserId());
}
@Override
public void installPackage(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName) {
installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
}
private void installCommon(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
int userId) {
if (!"file".equals(packageURI.getScheme())) {
throw new UnsupportedOperationException("Only file:// URIs are supported");
}
final String originPath = packageURI.getPath();
try {
mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
方法中传入了一个PackageInstallObserver对象,它是用户用来监听APK安装的最后结果的。PackageInstallObserver的定义如下:
public class PackageInstallObserver {
private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
PackageInstallObserver.this.onUserActionRequired(intent);
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode,
String msg, Bundle extras) {
PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,
extras);
}
};
/** {@hide} */
public IPackageInstallObserver2 getBinder() {
return mBinder;
}
public void onUserActionRequired(Intent intent) {
}
/**
* This method will be called to report the result of the package
* installation attempt.
*
* @param basePackageName Name of the package whose installation was
* attempted
* @param extras If non-null, this Bundle contains extras providing
* additional information about an install failure. See
* {@link android.content.pm.PackageManager} for documentation
* about which extras apply to various failures; in particular
* the strings named EXTRA_FAILURE_*.
* @param returnCode The numeric success or failure code indicating the
* basic outcome
* @hide
*/
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
}
}
其中,当apk安装结束时,系统会回调onPackageInstalled()接口通知用户当前apk安装的结果信息。
接着分析APK安装的流程,系统会调用PMS的installPackageAsUser()接口,将安装流程带入到PMS中:
@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");//检查调用进程的权限
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {//检查指定的用户是否被限制安装应用
try {
if (observer != null) {
observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
}
} catch (RemoteException re) {
}
return;
}
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
installFlags |= PackageManager.INSTALL_FROM_ADB;
} else {
// Caller holds INSTALL_PACKAGES permission, so we're less strict
// about installerPackageName.
installFlags &= ~PackageManager.INSTALL_FROM_ADB;
installFlags &= ~PackageManager.INSTALL_ALL_USERS;
}
UserHandle user;
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {//如果带有ISNASLL_ALL_USERS标记,则给所有用户安装
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}
// Only system components can circumvent runtime permissions when installing.
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");
}
final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
final Message msg = mHandler.obtainMessage(INIT_COPY);//要发送INIT_COPY消息,开始拷贝需要安装的Apk
final VerificationInfo verificationInfo = new VerificationInfo(
null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
//将安装参数信息保存到InstallParams对象中
final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
null /*packageAbiOverride*/, null /*grantedPermissions*/,
null /*certificates*/);
params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
mHandler.sendMessage(msg);//发送消息到PackageHandler中
}
首先是一些安装权限检查,之后会创建一个InstallParams实例,它里面封装了此次安装APK的各项参数;接着会发送INIT_COPY消息到Handler进行处理。
我们先总体看一下PMS应用安装过程中会涉及到的一些类型:
这些类型的作用就是封装一次应用安装过程的一些基本信息,我们只要注意它们的使用场景即可。INIT_COPY消息会触发APK文件的拷贝动作,它会由PMS::PackageHandler接收,而PackageHandler在PMS初始化时会被创建。PackageHandler主要负责这些APK安装消息的接收处理。我们先看INIT_COPY消息的处理过程:
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;//获取Apk安装参数
int idx = mPendingInstalls.size();//mPendingInstalls保存所有的需要安装的APk的安装信息
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) {//如果没有绑定DefaultContainerService服务;服务连接成功后,会置为true
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
// If this is the only one pending we might
// have to bind to the service again.
if (!connectToService()) {//异步过程.去绑定DefaultContainerService服务,绑定失败,需要报告错误信息;绑定成功后,会发送MCS_BOUND消息
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
params.traceCookie);
}
return;
} else {//绑定服务成功后,将当前的安装参数请求保存到mPendingInstalls
// Once we bind to the service, the first
// pending request will be processed.
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);//服务已经绑定,也会将安装信息保存到mPendingInstalls中
// 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;
}
mPendingInstalls是PackageHandler的一个成员,它保存所有的APK安装的InstallParams对象。mBound标识当前有没有绑定DefaultContainerService服务,之后的安装流程会调用它的一些方法。绑定DCS服务的处理由PackageHandler::connectToService()函数提供:
static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
DEFAULT_CONTAINER_PACKAGE,
"com.android.defcontainer.DefaultContainerService");
final private DefaultContainerConnection mDefContainerConn =
new DefaultContainerConnection();
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
IMediaContainerService imcs =
IMediaContainerService.Stub.asInterface(service);
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
}
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
}
}
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.SYSTEM)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}
如果服务绑定成功,mBound会置为true,并会发送MCS_BOUND消息,并附带DCS服务的Binder实例发送给PackageHandler。
接着看MCS_BOUND消息的处理:
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;//DefaultContainerService服务的代理
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
}
if (mContainerService == null) {
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();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
params.traceMethod, params.traceCookie);
}
return;
}
mPendingInstalls.clear();//情况mPendingInstalls
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {//DefaultContainerService服务连接正常
HandlerParams params = mPendingInstalls.get(0);//从首部拿出需要执行的安装参数信息
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
if (params.startCopy()) {//调用HandlerParrams接口,去执行apk的拷贝工作;此处是调用HandlerParrams::startCopy()
// 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首部内容,因为我们是从首部开始执行的
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {//如果mPendingInstalls已经没有内容,说明安装任务已经全部执行完毕,则会延迟10s后断开服务连接
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.
sendMessageDelayed(ubmsg, 10000);
}
} else {//否则,会再次发送MCS_BOUND消息,处理下一个安装请求
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing
// of next pending install.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting MCS_BOUND for next work");
mHandler.sendEmptyMessage(MCS_BOUND);//发送消息,处理下一个安装请求
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}
mContainerService对象保存了DefaultContainerService服务的Binder实例,它将被用来调用一些该服务中提供的方法。如果该实例为空,则表明服务连接异常,则需要对外报告错误,并清空mPendingInstalls集合;如果非空,则要处理APK的安装请求:
- 从mPendingInstalls首部取出要处理的安装参数对象,并调用InstallParams::startCopy()函数,开始进行APK的拷贝工作
- 如果拷贝工作完成,则会移除mPendingInstalls首部的对象
- 如果此时mPendingInstalls队列为空,表明所有的请求已经处理完了;则会通过发送MCS_UNBIND消息,延迟10s去断开与DCS服务的连接
- 如果此时mPendingInstalls对比不为空,表明当前还有安装请求需要处理,则会再次发送MCS_BOUND消息;进行新一轮的安装处理流程
因为传入的安装参数对象是InstallParams,根据之前的图示,我们直接看它父类的HandlerParams::startCopy()函数:
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
if (++mRetries > MAX_RETRIES) {//会尝试安装4次,如果4次都没有安装成功,则会退出
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP);//尝试4次后,都没有安装成功,则发送MCS_GIVE_UP消息放弃这次安装请求
handleServiceError();
return false;
} else {
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);//安装出错,则发送消息MCS_RECONNECT消息重新连接
res = false;
}
handleReturnCode();
return res;
}
HandlerParams::startCopy()为HandlerParams的子类所共有。首先一次apk的安装操作总共会尝试四次,如果四次都安装失败,则会发送MCS_GIVE_UP消息,放弃这次安装请求,并调用子类实现的handleServiceError()处理错误,然后直接返回;否则,调用子类实现的handleStartCopy()函数进程copy流程。handleStartCopy()处理成功后,还会调用子类实现的handleReturnCode()处理最后的结果。我们看InstallParams::handleStartCopy()的实现:
/*
* Invoke remote method to get package information and install
* location values. Override install location based on default
* policy if needed and then create install arguments based
* on the install location.
*/
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
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");
}
}
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {//如果既有安装在内部的标志,又有安装SD卡上的标志,则设置错误返回
// 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 if (onSd && ephemeral) {//此处与上述类似
Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);//获取安装包包含有应用信息的PacageInfoLite对象
if (DEBUG_EPHEMERAL && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
/*
* If we have too little free space, try to free cache
* before giving up.
*/
//如果安装的位置空间不够,会先尝试清除cache空间
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);
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold);
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
installFlags, packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
/*
* 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) {//如果该标志位依然是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.
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 if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_EPHEMERAL;
installFlags &= ~(PackageManager.INSTALL_EXTERNAL
|PackageManager.INSTALL_INTERNAL);
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
}
}
}
}
final InstallArgs args = createInstallArgs(this);//函数中会有分支处理,这里考虑FileInstallArgs实例创建情况,并会保存一份到InstallParams::mArgs
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果该标志位依然是INSTALL_SUCCEEDED,则说明前面的校验都通过
// TODO: http://b/22976637
// Apps installed for "all" users use the device owner to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
verifierUser = UserHandle.SYSTEM;
}
/*
* 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, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
//if部分是一段执行应用校验的代码,如果需要校验,则通过向系统中所有带有校验功能的组件发送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION广播来完成
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Query all live verifiers based on current user state
final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
+ verification.toString() + " with " + pkgLite.verifiers.length
+ " optional verifiers");
}
final int verificationId = mPendingVerificationToken++;
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
installerPackageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
installFlags);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
pkgLite.packageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
pkgLite.versionCode);
if (verificationInfo != null) {
if (verificationInfo.originatingUri != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
verificationInfo.originatingUri);
}
if (verificationInfo.referrer != null) {
verification.putExtra(Intent.EXTRA_REFERRER,
verificationInfo.referrer);
}
if (verificationInfo.originatingUid >= 0) {
verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
verificationInfo.originatingUid);
}
if (verificationInfo.installerUid >= 0) {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
verificationInfo.installerUid);
}
}
final PackageVerificationState verificationState = new PackageVerificationState(
requiredUid, args);
mPendingVerification.append(verificationId, verificationState);
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
*/
if (sufficientVerifiers != null) {
final int N = sufficientVerifiers.size();
if (N == 0) {
Slog.i(TAG, "Additional verifiers required, but none installed.");
ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
} else {
for (int i = 0; i < N; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
}
}
}
final ComponentName requiredVerifierComponent = matchComponentForVerifier(
mRequiredVerifierPackage, receivers);
if (ret == PackageManager.INSTALL_SUCCEEDED
&& mRequiredVerifierPackage != null) {
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
/*
* 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, verifierUser,
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 {//不需要校验,则调用FileInstallArgs::copyApk()继续后续的处理
/*
* No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
*/
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
这里总结下这段代码处理:
- 首先会进行一些安装标志的判断
- 调用DCS::getMinimalPackageInfo()方法获取该apk安装需要的大小及其他信息,信息会封装到PackageInfoLite对象中
- 如果检测到当前的目录下的大小不足以安装应用,还回去进行cache的清理工作
- 随后会以当前的InstallParams实例,创建FileInstallArgs对象,并保存一份到InstallParams对象的mArgs字段中
- 后续是一段组件校验工作,这里不做分析
- 最后FileInstallArgs::copyApk()函数,进行下一步处理
接着看FileInstallArgs::copyApk()函数:
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//通过PackageInstallService在/data/app/下生成临时文件
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
//为临时文件目录创建ParcelFileDescriptor描述符,它能在Binder间传递
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
@Override
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid filename: " + name);
}
try {
final File file = new File(codeFile, name);
final FileDescriptor fd = Os.open(file.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
Os.chmod(file.getAbsolutePath(), 0644);
return new ParcelFileDescriptor(fd);
} catch (ErrnoException e) {
throw new RemoteException("Failed to open: " + e.getMessage());
}
}
};
int ret = PackageManager.INSTALL_SUCCEEDED;
//使用DefaultContainerService::copyPackage()方法执行apk文件的复制
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
//安装应用中存在的native动态库,主要是从Apk打包文件中将它们提取出来放置
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
这里的处理有如下几个:
- 通过PackageInstallService为要安装的apk在/data/app/下生成一个零时文件tempDir,它的命名并不以.apk结尾
- 为该tempDir创建IParcelFileDescriptorFactory文件描述符,它可以在进程间传递
- 调用DefaultContainerService::copyPackage()方法执行apk临时文件的复制
- 最后再将apk中包含的一些库文件提取出来,放置到对应的lib/目录下
生成apk临时文件的调用是PackageInstallService::allocateStageDirLegacy():
@Deprecated
public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
synchronized (mSessions) {
try {
final int sessionId = allocateSessionIdLocked();
mLegacySessions.put(sessionId, true);
final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
prepareStageDir(stageDir);
return stageDir;
} catch (IllegalStateException e) {
throw new IOException(e);
}
}
}
private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
return new File(stagingDir, "vmdl" + sessionId + ".tmp");
}
临时文件的名称格式大致是:'vmdl-随机数.tmp'的形式。
如果一切过程都正常,至此,APK安装的第一部分的工做:APK文件的拷贝,就结束了;根据前面的流程,最后会调用InstallParams::handleReturnCode()执行返回结果的处理:
@Override
void handleReturnCode() {
// If mArgs is null, then MCS couldn't be reached. When it
// reconnects, it will try again to install. At that point, this
// will succeed.
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
因为InstallParams::mArgs我们之前赋值过,所以肯定不为空;继续调用processPendingInstall()函数:
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() {
public void run() {
mHandler.removeCallbacks(this);//消息移除,防止此处被重复调用
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果之前的处理顺利完成
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
installPackageTracedLI(args, res);//则需要去解析、装载应用
}
args.doPostInstall(res.returnCode, res.uid);
}
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
//后面一段都在执行备份操作
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
// there's a restore pass performed. Token values are >= 1.
int token;
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
PostInstallData data = new PostInstallData(args, res);
mRunningInstalls.put(token, data);
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
// Pass responsibility to the Backup Manager. It will perform a
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+ " to BM for possible restore");
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
try {
// TODO: http://b/22388012
if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
} else {
doRestore = false;
}
} catch (RemoteException e) {
// can't happen; the backup manager is local
} catch (Exception e) {
Slog.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
}
} else {
Slog.e(TAG, "Backup Manager not found!");
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);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);//此处发送POST_INSTALL消息,继续处理流程
mHandler.sendMessage(msg);
}
}
});
}
函数内会调用FileInstallArgs的doPreInstall()/doPostInstall()函数进行一些清理工作。其中PMS::installPackageTracedLI()函数的主要功能就是将当前安装的apk加入到它的管理体系中,以便之后统一管理;特殊的,该函数内部会调用FileInstallArgs::doReanme()函数将之前的apk备份文件重命名。具体的实现是扫描APK的过程,这部分之前已经有介绍过。略去之后的备份工作后,最后会发送POST_INSTALL消息,依旧是PackageHandler处理:
case POST_INSTALL: {//应用安装的收尾处理:主要动作是发送广播,通知系统中其他应用,开始某些处理工作:如果Launcher添加应用图标等
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
PostInstallData data = mRunningInstalls.get(msg.arg1);
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
if (data != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
final boolean grantPermissions = (args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final String[] grantedPermissions = args.installGrantPermissions;
// Handle the parent package
handlePackagePostInstall(parentRes, grantPermissions, killApp,
grantedPermissions, didRestore, args.installerPackageName,
args.observer);//各种广播的发送处理
// Handle the child packages
final int childCount = (parentRes.addedChildPackages != null)
? parentRes.addedChildPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
handlePackagePostInstall(childRes, grantPermissions, killApp,
grantedPermissions, false, args.installerPackageName,
args.observer);
}
// Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
} else {
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
由于需要安装的apk文件已经拷贝到了系统中,并且PMS也已经对它进行了统一管理;到此,APK的安装工作就基本完成了。但是,此时系统其它组件并不知道此时有新的APK安装进了系统中,所以这里需要发送一些广播给感兴趣的接收者,通知它们当前有新的apk安装完成了。这一部分最明显的就是Launcher了,我们安装apk后,Launcher上要添加图标,就是根据这部分内容来的。发送广播的主要函数是handlePackagePostInstall(),它的实现如下:
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, String[] grantedPermissions,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver) {
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// Send the removed broadcasts
if (res.removedInfo != null) {
res.removedInfo.sendPackageRemovedBroadcasts(killApp);
}
// Now that we successfully installed the package, grant runtime
// permissions if requested before broadcasting the install.
if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M) {
grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
}
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
// If this is the first time we have child packages for a disabled privileged
// app that had no children, we grant requested runtime permissions to the new
// children if the parent on the system image had them already granted.
if (res.pkg.parentPackage != null) {
synchronized (mPackages) {
grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
}
}
synchronized (mPackages) {
mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
}
final String packageName = res.pkg.applicationInfo.packageName;
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
int[] firstUsers = EMPTY_INT_ARRAY;
int[] updateUsers = EMPTY_INT_ARRAY;
if (res.origUsers == null || res.origUsers.length == 0) {
firstUsers = res.newUsers;
} else {
for (int newUser : res.newUsers) {
boolean isNew = true;
for (int origUser : res.origUsers) {
if (origUser == newUser) {
isNew = false;
break;
}
}
if (isNew) {
firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
} else {
updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
}
}
}
// Send installed broadcasts if the install/update is not ephemeral
if (!isEphemeral(res.pkg)) {
mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
// Send added for users that see the package for the first time
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/, null /*targetPackage*/,
null /*finishedReceiver*/, firstUsers);//首先要发送Intent.ACTION_PACKAGE_ADDED广播,表明系统中有新的apk被安装了
// Send added for users that don't see the package for the first time
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/, null /*targetPackage*/,
null /*finishedReceiver*/, updateUsers);
// Send replaced for users that don't see the package for the first time
if (update) {//如果当前安装是升级,则还需要发送更多的广播:Intent.ACTION_PACKAGE_REPLACED/Intent.ACTION_MY_PACKAGE_REPLACED
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUsers);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUsers);
} else if (launchedForRestore && !isSystemApp(res.pkg)) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
+ " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
}
sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
}
// Send broadcast package appeared if forward locked/external for all users
// treat asec-hosted packages like removable media on upgrade
if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {//如果安装的是foreword lock应用或是安装在SD卡上的应用,也有相关的广播要发送
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg
+ " is ASEC-hosted -> AVAILABLE");
}
final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
}
// Work that needs to happen on first install within each user
if (firstUsers != null && firstUsers.length > 0) {
synchronized (mPackages) {
for (int userId : firstUsers) {
// If this app is a browser and it's newly-installed for some
// users, clear any default-browser state in those users. 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, userId)) {
mSettings.setDefaultBrowserPackageNameLPw(null, userId);
}
// We may also need to apply pending (restored) runtime
// permission grants within these users.
mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
}
}
}
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
// Force a gc to clear up things
Runtime.getRuntime().gc();
// Remove the replaced package's older resources safely now
// We delete after a gc for applications on sdcard.
if (res.removedInfo != null && res.removedInfo.args != null) {
synchronized (mInstallLock) {
res.removedInfo.args.doPostDeleteLI(true);
}
}
}
// If someone is watching installs - notify them
if (installObserver != null) {//回调接口调用,反馈最终安装的结果
try {
Bundle extras = extrasForInstallResult(res);
installObserver.onPackageInstalled(res.name, res.returnCode,
res.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
主要处理就是发送各种广播,例如:
- Intent.ACTION_PACKAGE_ADDED:通知系统其它组件,当前有新的apk安装成功了,例如Launcher;Launcher再去向PMS查询所有带有主Activity的应用信息,更新显示。
最后再通过用户注册的Observer回调对象将安装结果回调给监听者。
分析到这里,一个APK的安装过程就简要地分析完成了。
http://m.blog.csdn.net/csdn_of_coder/article/details/74025409