我们知道在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(); try { mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName, verificationParams, null); } catch (RemoteException ignored) { } }
能够看到在installCommon终于调用了mPm.installPackage那mPm又是什么?能够发现mPM是一个IPackageManager,他在是ApplicationPackageManager的构造函数中传入的。那是什么时候调用构造函数的呐?在ContextImpl中调用getPackageManager时会进行调用,传入的pm在是ActivityThread中获取的。
@Override public PackageManager getPackageManager() { if (mPackageManager != null) { return mPackageManager; } IPackageManager pm = ActivityThread.getPackageManager(); if (pm != null) { // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; }
我们再来看看ActivityThread.getPackageManager()的获取过程。它的代码例如以下:
public static IPackageManager getPackageManager() { if (sPackageManager != null) { //Slog.v("PackageManager", "returning cur default = " + sPackageManager); return sPackageManager; } IBinder b = ServiceManager.getService("package"); //Slog.v("PackageManager", "default service binder = " + b); sPackageManager = IPackageManager.Stub.asInterface(b); //Slog.v("PackageManager", "default service = " + sPackageManager); return sPackageManager; }
从上面能够看到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来运行的
@Overridepublic 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类型。
这里传递过来的是toString的一个字符串。
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函数例如以下:
@Overridepublic 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)) { 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) { 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"); } 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.obj; 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(); return; } else { // Once we bind to the service, the first // pending request will be processed. 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) { mHandler.sendEmptyMessage(MCS_BOUND); } } break;}
能够看到首先取出參数params,这个params就是之前传入的InstallParams。接着获取等待安装队列的内容个数,因为初始mBound为false,因此会进入该推断。之后运行了connectToService函数。如个返回false表示连接失败,直接行使params的serviceError函数来结束当前运行,假设为true这时将params加入到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); mBound = true; return true; } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return false;}
能够看到这里bind到了一个service,service的名称是DefaultContainerService,这又是个什么service呐?而且在绑定之前先设置该进程的优先级为THREAD_PRIORITY_DEFAULT,运行完毕后再次设置为THREAD_PRIORITY_BACKGROUND。这里我们也没有看到有不论什么init/copy的操作。那init/copy操作到底在什么地方,绑定的这个服务又是什么?我们来分析一下代码,看到bindServiceAsUser中有一个connection參数。我们来看看connection參数,这个connection类型是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"); }}
能够看到当绑定成功后在onServiceConnected中将一个IBinder转换成了一个IMediaContainerService,这个又是什么呐?这个就是在onServiceConnected回调函数中依据參数传进来的IMediaContainerService.Stub的对象引用创建的一个远程代理对象。以后PackageManagerService服务通过该代理对象訪问DefaultContainerService服务。
DefaultContainerService是一个应用服务。详细负责实现APK等相关资源文件在内部或外部存储器上的存储工作,DefaultContainerService服务中提供了一个IMediaContainerService.Stub桩对象。
转换后,接下来我们看到这里又发送了一个what为MCS_BOUND的message,參数为之前获得的IMediaContainerService,这里也没有不论什么init/copy操作。那我们继续跟进看看该what运行了什么?
case MCS_BOUND: { if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } 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(); } 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()) { // 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); } } else { // 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); } } } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break;}
能够看到这里首先获取了传入的參数,假设參数为空,则调用HandlerParams的serviceError,而且清空mPendingInstalls列表,否则获取到等待安装列表中的第一个对象,就是我们最初始加入进的InstallParams,这里我们看到调用了InstallParams的startCopy函数。运行完毕后移除该參数,假设等待安装列表为空且当前绑定状态为true。则发一个what为MCS_UNBIND的解绑操作,否则就继续运行该操作。将等待列表中的一个一个运行。MCS_UNBIND与MCS_RECONNECT,这就不详细说了。MCS_UNBIND主要是解绑之前的链接,MCS_RECONNECT是又一次绑定链接,那我们继续看看startCopy函数:
final boolean startCopy() { boolean res; try { 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(); return false; } else { handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } handleReturnCode(); return res;}
这里最多会重试4次,假设超过最大次数则发送一个what为MCS_GIVE_UP的message表示安装失败,否则调用handleStartCopy。我们来看看handleStartCopy。因为取出的是InstallParams參数。因此这里调用的是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; PackageInfoLite pkgLite = null; if (onInt && onSd) { // Check if both bits are set. Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { 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); 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)) { 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 Listreceivers = 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; } 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) { /* * 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 { /* * No package verification is enabled, so immediately start * the remote call to initiate copy using temporary file. */ ret = args.copyApk(mContainerService, true); } } mRet = ret;}@Overridevoid 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()); try { ret = args.copyApk(mContainerService, true); } catch (RemoteException e) { Slog.e(TAG, "Could not contact the ContainerService"); } } else { broadcastPackageVerified(verificationId, originUri, PackageManager.VERIFICATION_REJECT, state.getInstallArgs().getUser()); } processPendingInstall(args, ret); mHandler.sendEmptyMessage(MCS_UNBIND); } break;}
验证完毕后发送一个验证完毕的广播,之后调用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 = currentStatus; res.uid = -1; res.pkg = null; 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 != 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"); try { if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) { 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); 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.Package pkg; try { pkg = pp.parsePackage(tmpPackageFile, parseFlags); } catch (PackageParserException e) { res.setError("Failed parse during installPackageLI", e); return; } ................. String oldCodePath = null; boolean systemApp = false; 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 // 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 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; } } } ............... // 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.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); } } } } } 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; } 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()) { // Enable SCAN_NO_DEX flag to skip dexopt at a later stage scanFlags |= SCAN_NO_DEX; try { 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; } } 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); } }}
主要是运行了下面操作:
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.packageName; if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg); final boolean dataDirExists = Environment .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists(); ........... try { 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 = false; try { final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags, currentTime, user); success = true; return res; } 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 = null; PackageSetting pkgSetting = null; // writer synchronized (mPackages) { // Check if we are renaming from an original package name. PackageSetting origPackage = null; String realName = null; 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.mRealPackage; if (!pkg.packageName.equals(renamed)) { // Callers into this function may have already taken // care of renaming the package; only do it here if // it is not already done. pkg.setPackageName(renamed); } } else { 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 = null; continue; } 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 = null; continue; } } else { if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " + pkg.packageName + " to old name " + origPackage.name); } break; } } } } ......... // 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. We // 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 = pkgSetting; 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.mSignatures; } else { 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"); } else { pkgSetting.signatures.mSignatures = pkg.mSignatures; String msg = "System package " + pkg.packageName + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } } } else { try { verifySignaturesLP(pkgSetting, pkg); // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSignatures; } 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(); int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); if (p.info.authority != null) { String names[] = p.info.authority.split(";"); for (int j = 0; j < names.length; j++) { if (mProvidersByAuthority.containsKey(names[j])) { PackageParser.Provider other = mProvidersByAuthority.get(names[j]); final String otherPackageName = ((other != null && other.getComponentName() != null) ? other.getComponentName().getPackageName() : "?"); throw new PackageManagerException( INSTALL_FAILED_CONFLICTING_PROVIDER, "Can't install because provider name " + names[j] + " (in package " + pkg.applicationInfo.packageName + ") is already used by " + otherPackageName); } } } } } if (pkg.mAdoptPermissions != null) { // This package wants to adopt ownership of permissions from // another package. for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) { final String origName = pkg.mAdoptPermissions.get(i); final PackageSetting orig = mSettings.peekPackageLPr(origName); if (orig != null) { if (verifyPackageUpdateLPr(orig, pkg)) { Slog.i(TAG, "Adopting permissions from " + origName + " to " + pkg.packageName); mSettings.transferPermissionsLPw(origName, pkg.packageName); } } } } } .......... File dataPath; if (mPlatformPackage == pkg) { // The system package is special. dataPath = new File(Environment.getDataDirectory(), "system"); pkg.applicationInfo.dataDir = dataPath.getPath(); } else { // This is a normal package, need to make its data directory. dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid, UserHandle.USER_OWNER, pkg.packageName); boolean uidError = false; if (dataPath.exists()) { int currentUid = 0; try { StructStat stat = Os.stat(dataPath.getPath()); currentUid = stat.st_uid; } catch (ErrnoException e) { Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e); } // If we have mismatched owners for the data path, we have a problem. if (currentUid != pkg.applicationInfo.uid) { boolean recovered = false; if (currentUid == 0) { // The directory somehow became owned by root. Wow. // This is probably because the system was stopped while // installd was in the middle of messing with its libs // directory. Ask installd to fix that. int ret = mInstaller.fixUid(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.uid); if (ret >= 0) { recovered = true; String msg = "Package " + pkg.packageName + " unexpectedly changed to uid 0; recovered to " + + pkg.applicationInfo.uid; reportSettingsProblem(Log.WARN, msg); } } if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0 || (scanFlags&SCAN_BOOTING) != 0)) { // If this is a system app, we can at least delete its // current data so the application will still work. int ret = removeDataDirsLI(pkg.volumeUuid, pkgName); if (ret >= 0) { // TODO: Kill the processes first // Old data gone! String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0 ? "System package " : "Third party package "; String msg = prefix + pkg.packageName + " has changed from uid: " + currentUid + " to " + pkg.applicationInfo.uid + "; old data erased"; reportSettingsProblem(Log.WARN, msg); recovered = true; // And now re-install the app. ret = createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.seinfo); if (ret == -1) { // Ack should not happen! msg = prefix + pkg.packageName + " could not have data directory re-created after delete."; reportSettingsProblem(Log.WARN, msg); throw new PackageManagerException( INSTALL_FAILED_INSUFFICIENT_STORAGE, msg); } } if (!recovered) { mHasSystemUidErrors = true; } } .............. } pkg.applicationInfo.dataDir = dataPath.getPath(); if (mShouldRestoreconData) { Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued."); mInstaller.restoreconData(pkg.volumeUuid, pkg.packageName, pkg.applicationInfo.seinfo, pkg.applicationInfo.uid); } } else { if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) Log.v(TAG, "Want this data dir: " + dataPath); } //invoke installer to do the actual installation int ret = createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.seinfo); .................. } pkgSetting.uidError = uidError; } final String path = scanFile.getPath(); final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting); if ((scanFlags & SCAN_NEW_INSTALL) == 0) { derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */); // Some system apps still use directory structure for native libraries // in which case we might end up not detecting abi solely based on apk // structure. Try to detect abi based on directory structure. if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() && pkg.applicationInfo.primaryCpuAbi == null) { setBundledAppAbisAndRoots(pkg, pkgSetting); setNativeLibraryPaths(pkg); } } else { // Set native library paths again. For moves, the path will be updated based on the // ABIs we've determined above. For non-moves, the path will be updated based on the // ABIs we determined during compilation, but the path will depend on the final // package path (after the rename away from the stage path). setNativeLibraryPaths(pkg); } if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path); final int[] userIds = sUserManager.getUserIds(); synchronized (mInstallLock) { // Make sure all user data directories are ready to roll; we're okay // if they already exist if (!TextUtils.isEmpty(pkg.volumeUuid)) { for (int userId : userIds) { if (userId != 0) { mInstaller.createUserData(pkg.volumeUuid, pkg.packageName, UserHandle.getUid(userId, pkg.applicationInfo.uid), userId, pkg.applicationInfo.seinfo); } } } // Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. We do not provide // this symlink for 64 bit libraries. if (pkg.applicationInfo.primaryCpuAbi != null && !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) { final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir; for (int userId : userIds) { if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName, nativeLibPath, userId) < 0) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Failed linking native library dir (user=" + userId + ")"); } } } } ............. ArrayList<PackageParser.Package> clientLibPkgs = null; // We also need to dexopt any apps that are dependent on this library. Note that // if these fail, we should abort the install since installing the library will // result in some apps being broken. if (clientLibPkgs != null) { if ((scanFlags & SCAN_NO_DEX) == 0) { for (int i = 0; i < clientLibPkgs.size(); i++) { PackageParser.Package clientPkg = clientLibPkgs.get(i); int result = mPackageDexOptimizer.performDexOpt(clientPkg, null /* instruction sets */, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI failed to dexopt clientLibPkgs"); } } } } // Request the ActivityManager to kill the process(only for existing packages) // so that we do not end up in a confused state while the user is still using the older // version of the application while the new one gets installed. if ((scanFlags & SCAN_REPLACING) != 0) { killApplication(pkg.applicationInfo.packageName, pkg.applicationInfo.uid, "replace pkg"); } // Also need to kill any apps that are dependent on the library. if (clientLibPkgs != null) { for (int i=0; i<clientLibPkgs.size(); i++) { PackageParser.Package clientPkg = clientLibPkgs.get(i); killApplication(clientPkg.applicationInfo.packageName, clientPkg.applicationInfo.uid, "update lib"); } } // Make sure we're not adding any bogus keyset info KeySetManagerService ksms = mSettings.mKeySetManagerService; ksms.assertScannedPackageValid(pkg); // writer synchronized (mPackages) { // We don't expect installation to fail beyond this point // Add the package's KeySets to the global KeySetManagerService ksms.addScannedPackageLPw(pkg); int N = pkg.providers.size(); StringBuilder r = null; int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); p.info.processName = fixProcessName(pkg.applicationInfo.processName, p.info.processName, pkg.applicationInfo.uid); mProviders.addProvider(p); p.syncable = p.info.isSyncable; if (p.info.authority != null) { String names[] = p.info.authority.split(";"); p.info.authority = null; for (int j = 0; j < names.length; j++) { if (j == 1 && p.syncable) { // We only want the first authority for a provider to possibly be // syncable, so if we already added this provider using a different // authority clear the syncable flag. We copy the provider before // changing it because the mProviders object contains a reference // to a provider that we don't want to change. // Only do this for the second authority since the resulting provider // object can be the same for all future authorities for this provider. p = new PackageParser.Provider(p); p.syncable = false; } if (!mProvidersByAuthority.containsKey(names[j])) { mProvidersByAuthority.put(names[j], p); if (p.info.authority == null) { p.info.authority = names[j]; } else { p.info.authority = p.info.authority + ";" + names[j]; } if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Registered content provider: " + names[j] + ", className = " + p.info.name + ", isSyncable = " + p.info.isSyncable); } } else { PackageParser.Provider other = mProvidersByAuthority.get(names[j]); Slog.w(TAG, "Skipping provider name " + names[j] + " (in package " + pkg.applicationInfo.packageName + "): name already used by " + ((other != null && other.getComponentName() != null) ? other.getComponentName().getPackageName() : "?")); } } } if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(p.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r); } N = pkg.services.size(); r = null; for (i=0; i<N; i++) { PackageParser.Service s = pkg.services.get(i); s.info.processName = fixProcessName(pkg.applicationInfo.processName, s.info.processName, pkg.applicationInfo.uid); mServices.addService(s); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(s.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r); } N = pkg.receivers.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.receivers.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mReceivers.addActivity(a, "receiver"); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r); } N = pkg.activities.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.activities.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mActivities.addActivity(a, "activity"); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r); } N = pkg.permissionGroups.size(); r = null; for (i=0; i<N; i++) { PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name); if (cur == null) { mPermissionGroups.put(pg.info.name, pg); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(pg.info.name); } } else { Slog.w(TAG, "Permission group " + pg.info.name + " from package " + pg.info.packageName + " ignored: original from " + cur.info.packageName); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append("DUP:"); r.append(pg.info.name); } } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r); } N = pkg.permissions.size(); r = null; for (i=0; i<N; i++) { PackageParser.Permission p = pkg.permissions.get(i); // Assume by default that we did not install this permission into the system. p.info.flags &= ~PermissionInfo.FLAG_INSTALLED; // Now that permission groups have a special meaning, we ignore permission // groups for legacy apps to prevent unexpected behavior. In particular, // permissions for one app being granted to someone just becuase they happen // to be in a group defined by another app (before this had no implications). if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { p.group = mPermissionGroups.get(p.info.group); // Warn for a permission in an unknown group. if (p.info.group != null && p.group == null) { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " in an unknown group " + p.info.group); } } ArrayMap<String, BasePermission> permissionMap = p.tree ? mSettings.mPermissionTrees : mSettings.mPermissions; BasePermission bp = permissionMap.get(p.info.name); // Allow system apps to redefine non-system permissions if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) { final boolean currentOwnerIsSystem = (bp.perm != null && isSystemApp(bp.perm.owner)); if (isSystemApp(p.owner)) { if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { // It's a built-in permission and no owner, take ownership now bp.packageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.applicationInfo.uid; bp.sourcePackage = p.info.packageName; p.info.flags |= PermissionInfo.FLAG_INSTALLED; } else if (!currentOwnerIsSystem) { String msg = "New decl " + p.owner + " of permission " + p.info.name + " is system; overriding " + bp.sourcePackage; reportSettingsProblem(Log.WARN, msg); bp = null; } } } if (bp == null) { bp = new BasePermission(p.info.name, p.info.packageName, BasePermission.TYPE_NORMAL); permissionMap.put(p.info.name, bp); } if (bp.perm == null) { if (bp.sourcePackage == null || bp.sourcePackage.equals(p.info.packageName)) { BasePermission tree = findPermissionTreeLP(p.info.name); if (tree == null || tree.sourcePackage.equals(p.info.packageName)) { bp.packageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.applicationInfo.uid; bp.sourcePackage = p.info.packageName; p.info.flags |= PermissionInfo.FLAG_INSTALLED; if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(p.info.name); } } else { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " ignored: base tree " + tree.name + " is from package " + tree.sourcePackage); } } else { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " ignored: original from " + bp.sourcePackage); } } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append("DUP:"); r.append(p.info.name); } if (bp.perm == p) { bp.protectionLevel = p.info.protectionLevel; } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r); } N = pkg.instrumentation.size(); r = null; for (i=0; i<N; i++) { PackageParser.Instrumentation a = pkg.instrumentation.get(i); a.info.packageName = pkg.applicationInfo.packageName; a.info.sourceDir = pkg.applicationInfo.sourceDir; a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs; a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs; a.info.dataDir = pkg.applicationInfo.dataDir; // TODO: Update instrumentation.nativeLibraryDir as well ? Does it // need other information about the application, like the ABI and what not ? a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; mInstrumentation.put(a.getComponentName(), a); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r); } if (pkg.protectedBroadcasts != null) { N = pkg.protectedBroadcasts.size(); for (i=0; i<N; i++) { mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i)); } } ............... } return pkg; }
这里主要做了下面操作:
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) { return res; } for (int user : users) { if (user != 0) { res = mInstaller.createUserData(volumeUuid, packageName, UserHandle.getUid(user, uid), user, seinfo); if (res < 0) { return res; } } } return res;}
这里终于调用了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 = 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.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; iAVAILABLE"); } 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 = true; } // 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) { 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;
万里长征最后一步,这里主要先将安装信息从安装列表中移除,这也是在之前processPendingInstall中加入的。包成功安装之后,在发送成功安装广播之前先获取运行时权限,获取权限后发送ACTION_PACKAGE_ADDED广播。假设是更新包再发送ACTION_PACKAGE_REPLACED和ACTION_MY_PACKAGE_REPLACED广播来通知其它应用,安装的广播发送完毕后发送一个资源更改的广播通知其它应用。假设该应用是一个浏览器,则先清除默认的浏览器设置。又一次检查浏览器设置。
上诉几步调用完毕之后。强制调用gc,来触发jvm进行垃圾回收操作。
gc调用后删除旧的安装信息,假设初始传入的IPackageInstallObserver2不为空,这回调调用方安装包安装完毕。
总结
到此大致分析了整个安装过程,还有非常多细节能够分析,比方parsePackage,之后能够再进行解析。整篇文章可能有理解错误的地方。望指出。