androidandroid下载软件安装装到哪里了

Android应用程序***过程浅析
我们知道在android中,***应用是由PackageManager来管理的,但是我们发现PackageManager是一个抽象类,他的installPackage方法也没有具体的实现。那在***过程中是怎么执行的呐?
查看代码可以知道ApplicationPackageManager是直接继承自PackageManager的,所以最终代码会调用ApplicationPackageManager下的installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName),而在installPackage里面又调用了installCommon。
installCommon的实现如下:
private void installCommon(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
if (!&file&.equals(packageURI.getScheme())) {
throw new UnsupportedOperationException(&Only file:// URIs are supported&);
if (encryptionParams != null) {
throw new UnsupportedOperationException(&ContainerEncryptionParams not supported&);
final String originPath = packageURI.getPath();
mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
verificationParams, null);
} catch (RemoteException ignored) {
可以看到在installCommon最终调用了mPm.installPackage那mPm又是什么?可以发现mPM是一个IPackageManager,他在是ApplicationPackageManager的构造函数中传入的,那是什么时候调用构造函数的呐?在ContextImpl中调用getPackageManager时会进行调用,传入的pm在是ActivityThread中创建的。
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageM
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
ActivityThread.getPackageManager()的代码如下:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v(&PackageManager&, &returning cur default = & + sPackageManager);
return sPackageM
IBinder b = ServiceManager.getService(&package&);
//Slog.v(&PackageManager&, &default service binder = & + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v(&PackageManager&, &default service = & + sPackageManager);
return sPackageM
从上面可以看到IPackageManager是进程间通信的客户端, 首先是IPackageManager是通过IPackageManager.aidl文件生成,同时生成了存根类IPackageManager.Stub,代理类:IPackageManager.Stub.Proxy,他是IBinder类型,那远端又是谁呐?远端就是PackageManagerService,PackageManagerService继承自IPackageManager.Stub,因此最终的调用都是通过aidl由PackageManagerService执行。因此我们主要来看看PackageManagerService中的执行过程。
主要有两种方式:
1:启动后扫描***,会调用PackageManagerService的scanPackageLI函数,
2:应用市场***,应用市场下载后会默认调用PackageManagerService的intallPackage函数,改函数最终也会调用到scanPackageLI,因此只需要分享第二种
我们可以大致看看代码调用的过程,流程图如下:
由于PackageManager最终是由PackageManagerService来执行的
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
installPackageAsUser(originPath, observer, installFlags, installerPackageName,
verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
主要传递了6个参数:
1,originPath,***包的位置,他必须是file类型活在content的URI类型。传递这里的是一个string类型。
2,observer,是一个IPackageInstallObserver类型,回调通知调用者***完成
3,installFlags,他的值是INSTALL_FORWARD_LOCK,INSTALL_REPLACE_EXISTING,INSTALL_ALLOW_TEST三个中的一个,INSTALL_FORWARD_LOCK表示***过程中是否锁定,INSTALL_REPLACE_EXISTING表示是否替换***包,INSTALL_ALLOW_TEST是否测试***包,如果有改标志,manifest必须配置android:testOnly
4,installerPackageName,***包包名
5,verificationParams,代表验证参数用于验证包***。
6,packageAbiOverride,一般传null
该函数调用了installPackageAsUser函数,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();
enforceCrossUserPermission(callingUid, userId, true, true, &installPackageAsUser&);
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
if (observer != null) {
observer.onPackageInstalled(&&, INSTALL_FAILED_USER_RESTRICTED, null, null);
} catch (RemoteException re) {
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
installFlags |= PackageManager.INSTALL_FROM_ADB;
// Caller holds INSTALL_PACKAGES permission, so we're less strict
// about installerPackageName.
installFlags &= ~PackageManager.INSTALL_FROM_ADB;
installFlags &= ~PackageManager.INSTALL_ALL_USERS;
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
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&);
verificationParams.setInstallerUid(callingUid);
final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
null, verificationParams, user, packageAbiOverride, null);
mHandler.sendMessage(msg);
该函数主要做了以下操作,第一强制获取权限,如果被拒绝则退出执行,接着设置installFlags参数,最后一步发送了一个what为INIT_COPY的message,参数为InstallParams,记住该参数,后面还会多次用到,看what的名称INIT_COPY,看起来是表达初始化并且拷贝,那是不是真是这样呐?我们去看看这个操作,这个操做是PackageHandler来执行的,PackageHandler继续字Handler,那我们来具体看看执行代码:
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.
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.
if (!connectToService()) {
Slog.e(TAG, &Failed to bind to media container service&);
params.serviceError();
// Once we bind to the service, the first
// pending request will be processed.
mPendingInstalls.add(idx, params);
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
可以看到首先取出参数params,这个params就是之前传入的InstallParams,接着获取等待***队列的内容个数,由于初始mBound为false,因此会进入该判断,之后执行了connectToService函数,如个返回false表示连接失败,直接行使params的serviceError函数来结束当前执行,如果为这将paramsa添加到mPendingInstalls的最后一个位置,connectToService连接又是什么呐?当前代码也没有执行任何与copy有段的操作啊?那我们去看看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);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
可以看到这里bind到了一个service,service的名称是DefaultContainerService,这又是个什么service呐?并且在绑定之前先设置该进程的优先级为THREAD_PRIORITY_DEFAULT,执行完成后再次设置为THREAD_PRIORITY_BACKGROUND,这里我们也没有看到有任何copy的操作,那copy操作究竟在什么地方,绑定的这个服务又是什么?我们来看看绑定的connection参数:
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&);
可以看到当绑定成功后将一个service转换成了一个IMediaContainerService,这个又是什么呐?这个就是在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建一个远程代理对象。以后PackageManagerService服务通过该代理对象访问DefaultContainerService服务。DefaultContainerService是一个应用服务,具体负责实现APK等相关资源文件在内部或外部存储器上的存储工作,DefaultContainerService服务中提供了一个IMediaContainerService.Stub桩对象。
接下来我们看到这里又发送了一个what为MCS_BOUND的message,参数为之前获得的IMediaContainerService,这里也没有任何copy操作,那我们继续跟进看看该what执行了什么?
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, &mcs_bound&);
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.
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();
mPendingInstalls.clear();
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()) {
// 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.
sendMessageDelayed(ubmsg, 10000);
// 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);
// Should never happen ideally.
Slog.w(TAG, &Empty queue&);
可以看到这里首先获取了传入的参数,如果参数为空,则调用HandlerParams的serviceError,并且清空mPendingInstalls列表,否则获取到等待***列表中的第一个对象,就是我们最初始添加进的InstallParams,这里我们看到调用了InstallParams的startCopy函数,执行完成后移除该参数,如果等待***列表为空且当前绑定状态为true,则发一个what为MCS_UNBIND的解绑操作,否则就继续执行该操作,将等待列表中的一个一个执行,MCS_UNBIND与MCS_RECONNECT,这就不详细说了,MCS_UNBIND主要是解绑之前的链接,MCS_RECONNECT是重新绑定链接,那我们继续看看startCopy函数:
final boolean startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, &startCopy & + mUser + &: & + this);
if (++mRetries & MAX_RETRIES) {
Slog.w(TAG, &Failed to invoke remote methods on default container service. Giving up&);
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
handleStartCopy();
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, &Posting install MCS_RECONNECT&);
mHandler.sendEmptyMessage(MCS_RECONNECT);
handleReturnCode();
这里会重试多次,如果超过最大次数则发送一个what为MCS_GIVE_UP的message表示***失败,否则调用handleStartCopy,我们来看看handleStartCopy,这里调用的是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;
throw new IllegalStateException(&Invalid stage location&);
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite =
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;
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);
* If we have too little free space, try to free cache
* before giving up.
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);
if (mInstaller.freeCache(null, sizeBytes + lowThreshold) &= 0) {
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;
// 设置ret
final InstallArgs args = createInstallArgs(this);
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)) {
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);
final List receivers = queryIntentReceivers(verification,
PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
0 /* TODO: Which userId? */);
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的参数
final PackageVerificationState verificationState = new PackageVerificationState(
requiredUid, args);
mPendingVerification.append(verificationId, verificationState);
final List sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
// Apps installed for &all& users use the device owner to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
verifierUser = UserHandle.OWNER;
* 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;
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) {
* 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() {
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.
* No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
ret = args.copyApk(mContainerService, true);
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);
首先设置installFlags参数,之后设置ret参数与verification参数,之后根据参数创建了InstallArgs参数,根据参数这里实际返回的是AsecInstallArgs类型,如果该包需要被验证,则发送一个广播进行包验证,否则直接拷贝apk,广播的onReceive中发送了一个what为CHECK_PENDING_VERIFICATION的message,参数为verificationId,handleReturnCode中直接调用了processPendingInstall来进行***处理,我们先来看看CHECK_PENDING_VERIFICATION的处理,这里最终也会调用到processPendingInstall。
case CHECK_PENDING_VERIFICATION: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.timeoutExtended()) {
final InstallArgs args = state.getInstallArgs();
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.i(TAG, &Verification timed out for & + originUri);
mPendingVerification.remove(verificationId);
int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
Slog.i(TAG, &Continuing with installation of & + originUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW,
state.getInstallArgs().getUser());
ret = args.copyApk(mContainerService, true);
} catch (RemoteException e) {
Slog.e(TAG, &Could not contact the ContainerService&);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT,
state.getInstallArgs().getUser());
processPendingInstall(args, ret);
mHandler.sendEmptyMessage(MCS_UNBIND);
验证完成后发送一个验证完成的广播,之后调用InstallArgs的copyApk函数拷贝包,这里的InstallArgs是什么类型呐?就是前面创建的AsecInstallArgs类型,因此执行的是AsecInstallArgs的copyApk函数,执行完成后调用processPendingInstall。copyApk主要是拷贝包到指定的目录下。这里就不详述了。接着看看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.returnCode = currentS
res.uid = -1;
res.removedInfo = new PackageRemovedInfo();
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
installPackageLI(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.removedPackage !=
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.
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.
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&);
if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {
bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
doRestore =
} catch (RemoteException e) {
// can' the backup manager is local
} catch (Exception e) {
Slog.e(TAG, &Exception trying to enqueue restore&, e);
doRestore =
Slog.e(TAG, &Backup Manager not found!&);
doRestore =
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);
mHandler.sendMessage(msg);
这里post一个Runnable来执行内部的逻辑,主要做了如下操作:
1,锁定后***包,通过调用installPackageLI来进行的
2,接下来都是执行备份操作,备份是通过BackupManagerService来完成的。备份完成后,通过发送what为POST_INSTALL的message来继续处理
我们先来看看installPackageLI的执行过程:
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
//...... 初始化参数....
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
final PackageParser.P
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError(&Failed parse during installPackageLI&, e);
.................
String oldCodePath =
boolean systemApp =
synchronized (mPackages) {
// Check if installing already existing package
if ((installFlags & 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
We must continue using the original name, so
// rename the new package here.
pkg.setPackageName(oldName);
pkgName = pkg.packageN
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
// we should replace it.
if (DEBUG_INSTALL) Slog.d(TAG, &Replace existing pacakge: & + pkgName);
// Prevent apps opting out from runtime permissions
if (replace) {
PackageParser.Package oldPackage = mPackages.get(pkgName);
final int oldTargetSdk = oldPackage.applicationInfo.targetSdkV
final int newTargetSdk = pkg.applicationInfo.targetSdkV
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.&);
...............
// Check whether the newly-scanned package wants to define an already-defined perm
int N = pkg.permissions.size();
for (int i = N-1; i &= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions..name);
if (bp != null) {
// If the defining package is signed with our cert, it's okay.
// 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);
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
// 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 &
+ .name + & already owned by & + bp.sourcePackage);
res.origPermission = .
res.origPackage = bp.sourceP
Slog.w(TAG, &Package & + pkg.packageName
+ & attempting to redeclare system permission &
+ .name + &; ignoring new declaration&);
pkg.permissions.remove(i);
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&);
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.primaryCpuAbiS
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiS
} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
scanFlags |= SCAN_NO_DEX;
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&);
// 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);
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, &Failed rename&);
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, volumeUuid, res);
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);
主要是执行了以下操作:
1,初始一些参数 2,调用PackageParser来解析包 3,判断是否是当前已有应用升级还是全新***,这两个都需要坚持签名
4,检测权限,检测新扫描的权限是否是已经定义的权限 5,根据条件是否进行derivePackageAbi操作,这个操作的注释为Derive
the ABI of a non-system package located at {@code scanFile}. This
information is derived purely on the basis of the contents of {@code
scanFile} and{@code cpuAbiOverride}. 6,开始intent filter验证
7,根据是否是已有应用进行升级还是全新***执行不同的操作
这里重要的主要是第2点和第7点,但是由于这里主要讲述android过程,因此对第2点不做详述,之后来详解该内容,我们假设这里是全新***着调用installNewPackageLI:
* Install a non-existing package.
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageN
if (DEBUG_INSTALL) Slog.d(TAG, &installNewPackageLI: & + pkg);
final boolean dataDirExists = Environment
.getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();
...........
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// remove package from internal structures.
Note that we want deletePackageX to
// delete the package data and cache directories that it created in
// scanPackageLocked, unless those directories existed before we even tried to
// install.
deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
res.removedInfo, true);
} catch (PackageManagerException e) {
res.setError(&Package couldn't be installed in & + pkg.codePath, e);
主要是调用了scanPackageLI来进行包的***,之后调用了updateSettingsLI,updateSettingsLI主要是更新了包的PackageSetting对象,主要更新了权限信息与***完成信息。这里我们继续查看scanPackageLI的执行:
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success =
final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
currentTime, user);
} finally {
if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
removeDataDirsLI(pkg.volumeUuid, pkg.packageName);
scanPackageLI主要调用了scanPackageDirtyLI,如果调用失败则调用removeDataDirsLI来移除***信息,scanPackageDirtyLI的代码如下:
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
final File scanFile = new File(pkg.codePath);
............
if (pkg.packageName.equals(&android&)) {
.............
................
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
SharedUserSetting suid =
PackageSetting pkgSetting =
synchronized (mPackages) {
// Check if we are renaming from an original package name.
PackageSetting origPackage =
String realName =
if (pkg.mOriginalPackages != null) {
// This package may need to be renamed to a previously
// installed name.
Let's check on that...
final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
if (pkg.mOriginalPackages.contains(renamed)) {
// This package had originally been installed as the
// original name, and we have already taken care of
// transitioning to the new one.
Just update the new
// one to continue using the old name.
realName = pkg.mRealP
if (!pkg.packageName.equals(renamed)) {
// Callers into this function may have already taken
// care of
only do it here if
// it is not already done.
pkg.setPackageName(renamed);
for (int i=pkg.mOriginalPackages.size()-1; i&=0; i--) {
if ((origPackage = mSettings.peekPackageLPr(
pkg.mOriginalPackages.get(i))) != null) {
// We do have the package already installed under its
// original name...
should we use it?
if (!verifyPackageUpdateLPr(origPackage, pkg)) {
// New package is not compatible with original.
origPackage =
} else if (origPackage.sharedUser != null) {
// Make sure uid is compatible between packages.
if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
Slog.w(TAG, &Unable to migrate data from & + origPackage.name
+ & to & + pkg.packageName + &: old uid &
+ origPackage.sharedUser.name
+ & differs from & + pkg.mSharedUserId);
origPackage =
if (DEBUG_UPGRADE) Log.v(TAG, &Renaming new package &
+ pkg.packageName + & to old name & + origPackage.name);
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi,
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
user, false);
...............
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
// Check all shared libraries and map to their actual file path.
// We only do this here for apps not on a system dir, because those
// are the only ones that can fail an install due to this.
// will take care of the system apps by updating all of their
// library paths after the scan is done.
updateSharedLibrariesLPw(pkg, null);
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgS
if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags)) {
if (checkUpgradeKeySetLP(pkgSetting, pkg)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mS
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
&Package & + pkg.packageName + & upgrade keys do not match the &
+ &previously installed version&);
pkgSetting.signatures.mSignatures = pkg.mS
String msg = &System package & + pkg.packageName
+ & retaining data.&;
reportSettingsProblem(Log.WARN, msg);
verifySignaturesLP(pkgSetting, pkg);
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mS
} catch (PackageManagerException e) {
// Verify that this new package doesn't have any content providers
// that conflict with existing packages.
Only do this if the
// package isn't already installed, since we don't want to break
// things that are installed.
if ((scanFlags & SCAN_NEW_INSTALL) != 0) {
final int N = pkg.providers.size();
for (i=0; i
这里主要做了以下操作:
1,检测路径代码路径是否存在不存在抛出异常
2,设置Package的applicationInfo信息
3,设置ResolverActivity信息
4,如果是系统程序则更改ResolverActivity信息
5,如果我们只***以及存在的包,则判断他的PackageSetting信息,如果路径不一致,测抛出异常
6,初始化包的代码与资源目录
7,检测我们是否需要重命名一个原始包
8,检测所有共享的libraries并且映射到真实的路径
9,如个是升级包则检测签名,如果新***包则验证签名
10,检测新包不含有与已经存在包冲突的provider
11,检测当前包对于其他包所拥有的权限
12,创建包data目录,并且重新调整uid,调用createDataDirsLI进行包的***
13,设置包的本地的Library路径
14,创建包的用户数据,调用createUserData
15,对包进行opt操作,调用performDexOpt,最终调用的还是Install的dexopt函数
16,如果是已存在的包,则调用ActivityManager杀死该进程
17,解析包的provider,并添加到ProviderIntentResolver,解析包的service,并添加到ServiceIntentResolver,解析包的receiver,并添加到ActivityIntentResolver,解析包的activity,并添加到ActivityIntentResolver,解析包的权利组与权限。最后解析instrumentation这个是测试用的,上述的解析主要是为了在应用中调用getPackageManager().resolveActivity等方法使用的。
上面主要是调用了createDataDirsLI来进行包的***:
private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) {
int[] users = sUserManager.getUserIds();
int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
if (res & 0) {
for (int user : users) {
if (user != 0) {
res = mInstaller.createUserData(volumeUuid, packageName,
UserHandle.getUid(user, uid), user, seinfo);
if (res & 0) {
这里最终调用了mInstaller的intall函数,mInstaller是一个InstallerConnection,InstallerConnection里面是通过输入输出流与一个LocalSocket进行***操作的,所以这里最终调用的InstallerConnection的intall函数,执行完成后如果user不为空,创建用户数据。
包的***过程到此就结束了,我们再回头看看POST_INSTALL进行了什么操作?
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, &Handling post-install for & + msg.arg1);
PostInstallData data = mRunningInstalls.get(msg.arg1);
mRunningInstalls.delete(msg.arg1);
boolean deleteOld =
if (data != null) {
InstallArgs args = data.
PackageInstalledInfo res = data.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
final String packageName = res.pkg.applicationInfo.packageN
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[] firstU
int[] updateUsers = new int[0];
if (res.origUsers == null || res.origUsers.length == 0) {
firstUsers = res.newU
firstUsers = new int[0];
for (int i=0; i ***AILABLE&);
int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
ArrayList pkgList = new ArrayList(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true,
pkgList,uidArray, null);
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
deleteOld =
// If this app is a browser and it's newly-installed for some
// users, clear any default-browser state in those users
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
Runtime.getRuntime().gc();
// We delete after a gc for applications
on sdcard.
if (deleteOld) {
synchronized (mInstallLock) {
res.removedInfo.args.doPostDeleteLI(true);
if (args.observer != null) {
Bundle extras = extrasForInstallResult(res);
args.observer.onPackageInstalled(res.name, res.returnCode,
res.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, &Observer no longer exists.&);
Slog.e(TAG, &Bogus post-install token & + msg.arg1);
万里长征最后一步,这里主要先将***信息从***列表中移除,这也是在之前processPendingInstall中添加的,包***成功之后,在发送***成功广播之前先获取运行时权限,获取权限后发送ACTION_PACKAGE_ADDED广播,如果是更新包再发送ACTION_PACKAGE_REPLACED和ACTION_MY_PACKAGE_REPLACED广播来通知其他应用,***的广播发送完成后发送一个资源更改的广播通知其他应用,如果该应用是一个,则先清除默认的浏览器设置,重新检查浏览器设置。
上诉几步调用完成之后,强制调用gc,来触发jvm进行垃圾回收操作。gc调用后删除旧的***信息,如果初始传入的IPackageInstallObserver2不为空,这回调调用方***包***完成。
到此大致分析了整个***过程,还有很多细节可以分析,比如parsePackage,之后可以在进行解析,整篇文字可能有理解错误的地方,望指出。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

参考资料

 

随机推荐