在Android中,通过发送Intent,就可以启动应用的安装过程,如下所示:
[java]
view plain
copy
- Uri uri = Uri.fromFile(new File(fileName));
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri, “application/vnd.android.package-archive”);
- startActivity(intent);
在Android的系统应用PackageInstaller中有一个PackageInstallerActivity会响应这个Intent。在这个Activity中,有两个重要的成员变量mPm,是ApplicationPackageManager的实例对象,也是PackageManagerService在应用中的代理对象。创建代码如下:
[java]
view plain
copy
- mPm = getPackageManager();
一、管理“安装会话”—-PackageInstallerService
PackageInstallerService是Android5.0新加入的服务,主要用于管理“安装会话(Installer Session)”。在Android5.0中,可以通过PackageInstallerService来分配一个SessionId,这个系统唯一的ID代表一次安装过程,如果一个应用的安装必须分成几个阶段来完成,即使设备重启了,也可以通过这个ID来继续安装过程。
PackageInstallerService中提供了接口createSession()创建一个Session:
[java]
view plain
copy
- public int createSession(SessionParams params, String installerPackageName, int userId) {
- try {
- return createSessionInternal(params, installerPackageName, userId);
- } catch (IOException e) {
- throw ExceptionUtils.wrap(e);
- }
- }
createSession方法将返回一个系统唯一值作为SessionID。如果希望再次使用这个Session,可以通过接口openSession打开它,代码如下:
[java]
view plain
copy
- public IPackageInstallerSession openSession(int sessionId) {
- try {
- return openSessionInternal(sessionId);
- } catch (IOException e) {
- throw ExceptionUtils.wrap(e);
- }
- }
- private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
- synchronized (mSessions) {
- final PackageInstallerSession session = mSessions.get(sessionId);
- if (session == null || !isCallingUidOwner(session)) {
- throw new SecurityException(“Caller has no access to session “ + sessionId);
- }
- session.open();
- return session;
- }
- }
openSession方法返回一个IPackageInstallerSession对象,它是Binder服务PackageInstallerSession的IBinder对象。在PackageInstallerService中mSessions数组保存了所有PackageInstallerSession对象,代码如下:
[java]
view plain
copy
- private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
当系统启动时,PackageManagerService初始化时会创建PackageInstallerService服务,在这个服务的初始化函数中,会读取/data/system目录下install_sessions.xml文件,这个文件中保存了系统中未完成的Install Session。PackageInstallerService会根据文件的内容创建PackageInstallerSession对象并插入到mSessions中。
PacakgeInstallerSession中保存了应用安装相关的数据,如,安装包的路径、安装的进度、中间数据保存的目录等。
二、应用安装第一阶段:复制文件
应用中可以调用PackageManager的installPackage()方法来开始安装过程,这个方法会调用PackageManagerService的installPackage()方法或installPackageAsUser()接口来执行安装过程。整个过程比较复杂,我们先看看安装序列图,如下:
应用安装的过程大概分成两个阶段,第一阶段把需要安装的应用复制到/data/app目录下,第二阶段是对apk文件进行扫描优化,然后装载到内存中。
PackageManagerService的installPackage方法用来给当前用户安装应用,而installPackageAsUser()方法给指定的用户安装应用。installPackage()方法只是使用当前用户的uid来调用installPackageAsUser()方法。代码如下:
[java]
view plain
copy
- @Override
- 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)) {//检查指定的用户是否被限制安装应用
- 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;//调用进程uid为0或2000,设置installFlags
- } 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) {//如果installFlags带有标记INSTALL_ALL_USERS,则给所有用户安装
- user = UserHandle.ALL;
- } else {
- user = new UserHandle(userId);
- }
- verificationParams.setInstallerUid(callingUid);
- final File originFile = new File(originPath);
- final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
- //保存参数到InstallParams对象并发送消息
- final Message msg = mHandler.obtainMessage(INIT_COPY);
- msg.obj = new InstallParams(origin, observer, installFlags,
- installerPackageName, verificationParams, user, packageAbiOverride);
- mHandler.sendMessage(msg);
- }
installPackageAsUser()方法首先检查调用进程是否有安装应用的权限,再检查调用进程的所属用户是否有权限安装应用,最后检查指定的用户是否被限制安装应用。如果参数installFlags带有标记INSTALL_ALL_USERS,则该应用将给系统中所有用户安装,否则只给指定的用户安装。
installPackageAsUser()方法,把调用的参数保存在InstallParams对象中,然后发送INIT_COPY消息。InstallParams是安装过程中主要的数据结构,从HandleParams类派生,用来记录安装应用的参数。从HandleParams派生的还有MoveParams和MeasureParams,MoveParams用于将应用移动到SD卡,MeasureParams用于方法getPackageSizeInfo中。InstallParams成员变量mArgs,是FileInstallArgs类型,用来执行apk文件的复制。
我们看下INIT_COPY消息的处理,在doHandleMessage()方法中,如下:
[java]
view plain
copy
- 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()) {//绑定DefaultContainerService服务
- Slog.e(TAG, “Failed to bind to media container service”);
- params.serviceError();
- return;//连接服务失败,退出
- } else {
- // Once we bind to the service, the first<span style=”font-size: 11.8181819915771px; font-family: Arial, Helvetica, sans-serif;”>连接成功,把安装信息保存到mPedingInstalls中</span>
- // 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) {//如果mPendingInstalls只有一项,立刻发MCS_BOUND消息
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- break;
- }
在INIT_COPY消息的处理中将绑定DefaultContainerService,因为这是一个异步的过程,要等待绑定的结果通过onServiceConnected()返回,所以,这里将安装的参数信息放到mPendingInstalls列表中。如果这个service以前就绑定好了,现在不在需要再绑定,安装信息也会先放到mPendingInstalls中。如果有多个安装请求同时到达,通过mPendingInstalls列表可以对它们进行排队。如果列表中只有一项,说明没有更多的安装请求,此时会立即发送MCS_BOUND消息,进入下一步的处理。而onServiceConnected()方法的处理同样是发送MCS_BOUND消息,如下:
[java]
view plain
copy
- 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”);
- }
- };
我们看下MCS_BOUND消息是怎么处理的,如下:
[java]
view plain
copy
- case MCS_BOUND: {
- if (DEBUG_INSTALL) Slog.i(TAG, “mcs_bound”);
- if (msg.obj != null) {
- mContainerService = (IMediaContainerService) msg.obj;
- }
- if (mContainerService == null) {//如果DefaultContainerService没有连接成功
- // Something seriously wrong. Bail out
- Slog.e(TAG, “Cannot bind to media container service”);
- for (HandlerParams params : mPendingInstalls) {
- // Indicate service bind error
- params.serviceError();//通过参数中带的回调接口通知调用者出错了
- }
- mPendingInstalls.clear();
- } 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) {//如果没有安装信息了,发送延时10秒的MCS_UNBIND消息
- 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.mPendingInstalls还有安装信息,发送MCS_BOUND消息
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- “Posting MCS_BOUND for next work”);
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- }
- } else {
- // Should never happen ideally.
- Slog.w(TAG, “Empty queue”);
- }
- break;
- }
MCS_BOUND消息的处理过程就是调用InstallParams类的startCopy()方法来执行安装。只要mPendingInstalls中还有安装信息,就会重复发送MCS_BOUND消息,知道所有的应用都安装完毕,然后发送一个延时10秒的MCS_UNBIND消息。
MCS_UNBIND消息的处理如下:
[java]
view plain
copy
- case MCS_UNBIND: {
- // If there is no actual work left, then time to unbind.
- if (DEBUG_INSTALL) Slog.i(TAG, “mcs_unbind”);
- if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
- if (mBound) {
- if (DEBUG_INSTALL) Slog.i(TAG, “calling disconnectService()”);
- disconnectService();//断开与DefaultContainerService的连接
- }
- } else if (mPendingInstalls.size() > 0) {
- // There are more pending requests in queue.
- // Just post MCS_BOUND message to trigger processing
- // of next pending install.
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- break;
- }
处理MCS_UNBIND消息时,如果发现mPendingInstalls列表中又有数据了,则发送MCS_BOUND消息继续安装;否则断开和DefaultContainerService的连接,安装过程就此结束。
继续分析下start_copy()方法,InstallParams类继承HandlerParams抽象类,InstallParams类没有重写startCopy方法,因此调用HandlerParams的startCopy方法,如下:
[java]
view plain
copy
- final boolean startCopy() {
- boolean res;
- try {
- if (DEBUG_INSTALL) Slog.i(TAG, “startCopy “ + mUser + “: “ + this);
- if (++mRetries > MAX_RETRIES) {//如果重试超过4次,退出;MAX_RETRIES=4
- Slog.w(TAG, “Failed to invoke remote methods on default container service. Giving up”);
- mHandler.sendEmptyMessage(MCS_GIVE_UP);//发送MCS_GIVE_UP消息
- handleServiceError();
- return false;
- } else {
- handleStartCopy();//执行安装
- res = true;
- }
- } catch (RemoteException e) {
- if (DEBUG_INSTALL) Slog.i(TAG, “Posting install MCS_RECONNECT”);
- mHandler.sendEmptyMessage(MCS_RECONNECT);//安装出错,发送MCS_RECONNECT消息,重新连接
- res = false;
- }
- handleReturnCode();
- return res;
- }
startCopy()方法通过调用handleStartCopy方法来完成安装过程。但是考虑到安装过程的不确定性,startCopy()主要的工作是进行错误处理,如果捕获到handleStartCopy()方法抛出的异常,startCopy方法将发送消息MCS_RECONNECT。
[java]
view plain
copy
- case MCS_RECONNECT: {
- if (DEBUG_INSTALL) Slog.i(TAG, “mcs_reconnect”);
- if (mPendingInstalls.size() > 0) {
- if (mBound) {
- disconnectService();
- }
- if (!connectToService()) {
- Slog.e(TAG, “Failed to bind to media container service”);
- for (HandlerParams params : mPendingInstalls) {
- // Indicate service bind error
- params.serviceError();
- }
- mPendingInstalls.clear();
- }
- }
- break;
- }
在MCS_RECONNECT的处理中,会重新绑定DefaultContainerService,如果绑定成功,安装过程就会重新开始,startCopy方法会被再次调用。重试的次数记录在mRetries变量中,如果超过4次,安装失败。如果安装成功,调用handleReturnCode方法继续处理。先分析下handleStartCopy方法,如下:
[java]
view plain
copy
- 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) {//如果既有安装在内部的标志,又有安装在SD卡上的标志,设置错误后返回
- // Check if both bits are set.
- Slog.w(TAG, “Conflicting flags specified for installing on both internal and external”);
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else {
- pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
- packageAbiOverride);//获取安装包包含有应用信息的PackageInfoLite对象
- /*
- * If we have too little free space, try to free cache
- * before giving up.如果安装的位置空间不够,释放cache空间
- */
- if (!origin.staged && pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- // TODO: focus freeing disk space on the target device
- final StorageManager storage = StorageManager.from(mContext);
- long lowThreshold = storage.getStorageLowBytes(
- Environment.getDataDirectory());
- final long sizeBytes = mContainerService.calculateInstalledSize(
- origin.resolvedPath, isForwardLocked(), packageAbiOverride);
- if (mInstaller.freeCache(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;
- }
- }
- }
- ……
- 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)) {<span style=“font-family: Arial, Helvetica, sans-serif; font-size: 12px;”> </span>
[java]
view plain
copy
- <pre name=“code” class=“java” style=“font-size: 11.8181819915771px;”> //执行应用的校验,校验的方法是通过向带校验功能的组件发Intent来完成。
…… } else { /* * No package verification is enabled, so immediately start * the remote call to initiate copy using temporary file. *///如果无需校验,调用IntallArgs的copyApk方法继续处理 ret = args.copyApk(mContainerService, true); } } mRet = ret; }
handleStartCopy()方法先调用getMinimalPackageInfo()来确定安装位置是否还有足够空间,并在PackageInfoLite对象的recommendedInstallLocation变量中记录错误原因。发现安装空间不够后,handleStartCopy()方法会调用installer的freeCache()方法来释放一部分空间。
接下来handleStartCopy()方法会调用createInstallArgs()来创建InstallArgs对象,在createInstallArgs()方法中,如果应用要求安装在SD卡上,或者是一个forward lock的应用,则创建AsecInstallArgs对象,否则创建FileInstallArgs对象。这样安装流程将会分化,这里主要分析下FileInstallArgs。如下:
[java]
view plain
copy
- private InstallArgs createInstallArgs(InstallParams params) {
- if (installOnSd(params.installFlags) || params.isForwardLocked()) {
- return new AsecInstallArgs(params);
- } else {
- return new FileInstallArgs(params);
- }
- }
接下来handleStartCopy()方法处理APK的校验,这个校验的过程是通过发送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION给系统中所有接收该Intent的应用来完成的。如果无需校验,则直接调用InstallArgs对象的copyApk()方法,FileInstallArgs继承了InstallArgs类,这里调用的是FileInstallArgs类的copyApk()方法,如下:
[java]
view plain
copy
- int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
- if (origin.staged) {
- Slog.d(TAG, origin.file + ” already staged; skipping copy”);
- codeFile = origin.file;
- resourceFile = origin.file;
- return PackageManager.INSTALL_SUCCEEDED;
- }
- try {//在/data/app/下生成临时文件
- final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
- codeFile = tempDir;
- resourceFile = tempDir;
- } catch (IOException e) {
- Slog.w(TAG, “Failed to create copy file: “ + e);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
- //为临时文件创建文件描述符ParcelFileDescriptor,它能通过Binder传递
- final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
- @Override
- public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
- if (!FileUtils.isValidExtFilename(name)) {
- throw new IllegalArgumentException(“Invalid filename: “ + name);
- }
- try {
- final File file = new File(codeFile, name);
- final FileDescriptor fd = Os.open(file.getAbsolutePath(),
- O_RDWR | O_CREAT, 0644);
- Os.chmod(file.getAbsolutePath(), 0644);
- return new ParcelFileDescriptor(fd);
- } catch (ErrnoException e) {
- throw new RemoteException(“Failed to open: “ + e.getMessage());
- }
- }
- };
- //使用服务DefaultContainerService的copyPackage()方法复制文件
- int ret = PackageManager.INSTALL_SUCCEEDED;
- ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, “Failed to copy package”);
- return ret;
- }
- //安装应用中自带的native的动态库
- final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(codeFile);
- ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- abiOverride);
- } catch (IOException e) {
- Slog.e(TAG, “Copying native libraries failed”, e);
- ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- } finally {
- IoUtils.closeQuietly(handle);
- }
- return ret;
- }
copyApk()同样是调用DefaultContainerService的copyPackage()将应用的文件复制到/data/app下。如果应用中还有native的动态库,也会把包在apk文件中的动态库的文件提取出来。执行完copyApk后,安装的第一阶段工作就完成了,应用安装到了/data/app目录下。
三、装载应用
第二阶段就是将应用的格式转化为oat格式,为应用创建数据目录,最后把应用的信息装载进PMS的数据结构中。
在前面的startCopy()方法中已经看到,最后它会调用handleReturnCode()方法,如下:
[java]
view plain
copy
- 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);
- }
- }
handleReturnCode()方法只是调用了processpendingInstall()方法,如下:
[java]
view plain
copy
- 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) {//发送POST_INSTALL消息
- // 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);
- }
- }
- });
- }
processPendingInstall()方法中post了一个消息,这样安装过程将以异步的方式继续执行。在post消息的处理中,首先调用installPackageLI()来装载应用,接下来的一大段代码都是执行备份操作,备份是通过BackupManagerService来完成的。备份完成后,通过发送POST_INSTALL消息来继续处理。先分析下installPackageLI()方法,如下:
[java]
view plain
copy
- private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
- final int installFlags = args.installFlags;
- String installerPackageName = args.installerPackageName;
- File tmpPackageFile = new File(args.getCodePath());
- boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
- boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
- boolean replace = false;
- final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
- // Result object to be returned
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
- if (DEBUG_INSTALL) Slog.d(TAG, “installPackageLI: path=” + tmpPackageFile);
- if (true != mSecurityBridge.approveAppInstallRequest(
- args.getResourcePath(),
- Uri.fromFile(args.origin.file).toSafeString())) {
- res.returnCode = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
- return;
- }
- // Retrieve PackageSettings and parse package创建apk文件的解析器
- final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
- | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
- | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
- PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setDisplayMetrics(mMetrics);
- final PackageParser.Package pkg;
- try {//解析apk文件
- pkg = pp.parsePackage(tmpPackageFile, parseFlags);
- } catch (PackageParserException e) {
- res.setError(“Failed parse during installPackageLI”, e);
- return;
- }
- // Mark that we have an install time CPU ABI override.
- pkg.cpuAbiOverride = args.abiOverride;
- String pkgName = res.name = pkg.packageName;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
- if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
- res.setError(INSTALL_FAILED_TEST_ONLY, “installPackageLI”);
- return;
- }
- }
- if (android.app.AppOpsManager.isStrictEnable()
- && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)
- && Secure.getInt(mContext.getContentResolver(),
- Secure.INSTALL_NON_MARKET_APPS, 0) <= 0) {
- res.returnCode = PackageManager.INSTALL_FAILED_UNKNOWN_SOURCES;
- return;
- }
- //收集应用的签名
- try {
- pp.collectCertificates(pkg, parseFlags);
- pp.collectManifestDigest(pkg);
- } catch (PackageParserException e) {
- res.setError(“Failed collect during installPackageLI”, e);
- return;
- }
- /* If the installer passed in a manifest digest, compare it now. */
- if (args.manifestDigest != null) {
- if (DEBUG_INSTALL) {
- final String parsedManifest = pkg.manifestDigest == null ? “null”
- : pkg.manifestDigest.toString();
- Slog.d(TAG, “Comparing manifests: “ + args.manifestDigest.toString() + ” vs. “
- + parsedManifest);
- }
- if (!args.manifestDigest.equals(pkg.manifestDigest)) {
- res.setError(INSTALL_FAILED_PACKAGE_CHANGED, “Manifest digest changed”);
- return;
- }
- } else if (DEBUG_INSTALL) {
- final String parsedManifest = pkg.manifestDigest == null
- ? “null” : pkg.manifestDigest.toString();
- Slog.d(TAG, “manifestDigest was not present, but parser got: “ + parsedManifest);
- }
- // Get rid of all references to package scan path via parser.
- pp = null;
- String oldCodePath = null;
- boolean systemApp = false;
- synchronized (mPackages) {
- // 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);
- }
- }
[java]
view plain
copy
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- if (DEBUG_INSTALL) Slog.d(TAG, “Existing package: “ + ps);
- // Quick sanity check that we’re signed correctly if updating;
- // we’ll check this again later when scanning, but we want to
- // bail early here before tripping over redefined permissions.
- if (!ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) {
- try {
- verifySignaturesLP(ps, pkg);
- } catch (PackageManagerException e) {
- res.setError(e.error, e.getMessage());
- return;
- }
- } else {
- if (!checkUpgradeKeySetLP(ps, pkg)) {
- res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, “Package “
- + pkg.packageName + ” upgrade keys do not match the “
- + “previously installed version”);
- return;
- }
- }
- 存在同名的应用,如果存在,检查应用是否带有系统标志
- oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
- if (ps.pkg != null && ps.pkg.applicationInfo != null) {
- systemApp = (ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SYSTEM) != 0;
- }
- res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
- }
。。。。。。
installPackageLI()方法首先解析了安装的应用文件,得到解析的结果后,主要是判断新安装的应用是否和系统中已安装的应用构成升级关系,如果是,调用replacePackageLI()方法继续处理,否则调用installNewPackageLI()方法处理。
再接着看下POST_INSTALL消息是如何处理的:
[java]
view plain
copy
- 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) {
- res.removedInfo.sendBroadcast(false, true, false);
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.uid);
- 。。。。。。
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- res.pkg.applicationInfo.packageName,
- extras, null, null, firstUsers);//发送ACTION_PACKAGE_ADDED广播
- final boolean update = res.removedInfo.removedPackage != null;
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- res.pkg.applicationInfo.packageName,
- extras, null, null, updateUsers);
- if (update) {//如果是升级包,还会发送更多的广播
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- res.pkg.applicationInfo.packageName,
- extras, null, null, updateUsers);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null, null,
- res.pkg.applicationInfo.packageName, null, updateUsers);
- // treat asec-hosted packages like removable media on upgrade
- if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {//如果是forward lock应用,或安装在SD卡上的应用,发送广播
- if (DEBUG_INSTALL) {
- Slog.i(TAG, “upgrading pkg “ + res.pkg
- + ” is ASEC-hosted -> AVAILABLE”);
- }
- int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
- ArrayList<String> pkgList = new ArrayList<String>(1);
- pkgList.add(res.pkg.applicationInfo.packageName);
- sendResourcesChangedBroadcast(true, true,
- pkgList,uidArray, null);
- }
- }
- if (res.removedInfo.args != null) {
- // Remove the replaced package’s older resources safely now
- deleteOld = true;
- }
- // 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);
- }
- sLatestSecureContainerList = PackageHelper.getSecureContainerList();
- }
POST_INSTALL消息的处理主要就是发送广播,应用安装完成后要通知系统中其他的应用开始处理,例如,Launcher中需要增加应用的图标等。发完广播安装也就结束了。最后通过参数中的回调接口通知调用者安装的结果。
四、卸载应用
PMS还会监视应用目录的变化,做出相应的处理。
卸载应用的接口是deletePackage(),如下:
[java]
view plain
copy
- public void deletePackage(final String packageName,
- final IPackageDeleteObserver2 observer, final int userId, final int flags) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.DELETE_PACKAGES, null);//检查执行权限
- final int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- “deletePackage for user “ + userId);
- }
- if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
- try {//如果用户权限不够,发送错误信息
- observer.onPackageDeleted(packageName,
- PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
- } catch (RemoteException re) {
- }
- return;
- }
- boolean uninstallBlocked = false;
- if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {
- int[] users = sUserManager.getUserIds();
- for (int i = 0; i < users.length; ++i) {
- if (getBlockUninstallForUser(packageName, users[i])) {
- uninstallBlocked = true;
- break;
- }
- }
- } else {
- uninstallBlocked = getBlockUninstallForUser(packageName, userId);
- }
- if (uninstallBlocked) {
- try {
- observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,
- null);
- } catch (RemoteException re) {
- }
- return;
- }
- if (DEBUG_REMOVE) {
- Slog.d(TAG, “deletePackageAsUser: pkg=” + packageName + ” user=” + userId);
- }
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {//post消息,在消息处理方法中执行卸载应用的操作
- public void run() {
- mHandler.removeCallbacks(this);
- final int returnCode = deletePackageX(packageName, userId, flags);
- if (observer != null) {
- try {
- observer.onPackageDeleted(packageName, returnCode, null);//发送卸载应用的结果
- } catch (RemoteException e) {
- Log.i(TAG, “Observer no longer exists.”);
- } //end catch
- } //end if
- } //end run
- });
- }
deletePackage()方法检查调用者的权限后,post了一个消息。在消息的处理方法中继续执行卸载操作,这样就避免了Binder调用时间过长。实际的卸载是通过调用deletePackageX()方法完成的,如下:
[java]
view plain
copy
- private int deletePackageX(String packageName, int userId, int flags) {
- final PackageRemovedInfo info = new PackageRemovedInfo();
- final boolean res;
- final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
- ? UserHandle.ALL : new UserHandle(userId);
- //检查userId代表的用户是否有权限删除这个应用
- if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
- Slog.w(TAG, “Not removing package “ + packageName + “: has active device admin”);
- return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
- }
- boolean removedForAllUsers = false;
- boolean systemUpdate = false;
- // for the uninstall-updates case and restricted profiles, remember the per-
- // userhandle installed state
- int[] allUsers;
- boolean[] perUserInstalled;
- synchronized (mPackages) {
- PackageSetting ps = mSettings.mPackages.get(packageName);//获取应用在mSettings中的包的信息
- allUsers = sUserManager.getUserIds();
- perUserInstalled = new boolean[allUsers.length];
- for (int i = 0; i < allUsers.length; i++) {//检查并记录系统中所有用户是否都安装了这个应用
- perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
- }
- }
- synchronized (mInstallLock) {
- if (DEBUG_REMOVE) Slog.d(TAG, “deletePackageX: pkg=” + packageName + ” user=” + userId);
- res = deletePackageLI(packageName, removeForUser,
- true, allUsers, perUserInstalled,
- flags | REMOVE_CHATTY, info, true);//调用deletePackageLI方法来卸载应用
- systemUpdate = info.isRemovedPackageSystemUpdate;
- if (res && !systemUpdate && mPackages.get(packageName) == null) {
- removedForAllUsers = true;
- }
- if (DEBUG_REMOVE) Slog.d(TAG, “delete res: systemUpdate=” + systemUpdate
- + ” removedForAllUsers=” + removedForAllUsers);
- }
- if (res) {
- info.sendBroadcast(true, systemUpdate, removedForAllUsers);
- // If the removed package was a system update, the old system package
- // was re-enabled; we need to broadcast this information
- if (systemUpdate) {//如果卸载的应用是某个系统应用的升级包,卸载它将导致低版本的系统应用重新使用;因此需要发送广播通知这种变化
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
- ? info.removedAppId : info.uid);
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, null, null, null);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, null, null, null);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
- null, packageName, null, null);
- }
- }
- // Force a gc here.
- Runtime.getRuntime().gc();
- // Delete the resources here after sending the broadcast to let
- // other processes clean up before deleting resources.
- if (info.args != null) {
- synchronized (mInstallLock) {
- info.args.doPostDeleteLI(true);//调用FileInstallArgs的方法做清理工作
- }
- }
- return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
- }
deletePackageX()方法收集了应用在不同用户下的安装情况后,调用deletePackageLI方法继续卸载。如果删除的是某个系统应用的升级包,这里还会发出广播通知以前的应用又重新使用了。deletePackageLI方法如下:
[java]
view plain
copy
- private boolean deletePackageLI(String packageName, UserHandle user,
- boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo,
- boolean writeSettings) {
- if (packageName == null) {
- Slog.w(TAG, “Attempt to delete null packageName.”);
- return false;
- }
- if (DEBUG_REMOVE) Slog.d(TAG, “deletePackageLI: “ + packageName + ” user “ + user);
- PackageSetting ps;
- boolean dataOnly = false;
- int removeUser = –1;
- int appId = –1;
- synchronized (mPackages) {
- ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- Slog.w(TAG, “Package named ‘” + packageName + “‘ doesn’t exist.”);
- return false;
- }
- if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
- && user.getIdentifier() != UserHandle.USER_ALL) {
- // 如果调用者只要求卸载某个用户下的应用
- if (DEBUG_REMOVE) Slog.d(TAG, “Only deleting for single user”);
- ps.setUserState(user.getIdentifier(),
- COMPONENT_ENABLED_STATE_DEFAULT,
- false, //installed
- true, //stopped
- true, //notLaunched
- false, //hidden
- null, null, null,
- false // blockUninstall
- );
- if (!isSystemApp(ps)) {
- if (ps.isAnyInstalled(sUserManager.getUserIds())) {
- // 如果还有其他用户在使用这个应用,删除应用在这个被删除用户下的数据
- if (DEBUG_REMOVE) Slog.d(TAG, “Still installed by other users”);
- removeUser = user.getIdentifier();
- appId = ps.appId;
- mSettings.writePackageRestrictionsLPr(removeUser);
- } else {
- // We need to set it back to ‘installed’ so the uninstall
- // broadcasts will be sent correctly.没有用户使用了,全部删除应用
- if (DEBUG_REMOVE) Slog.d(TAG, “Not installed by other users, full delete”);
- ps.setInstalled(true, user.getIdentifier());
- }
- } else {
- // 系统应用,可能别的用户还在使用它;因此,这里只清除应用在需要删除的用户目录下的数据目录;
- if (DEBUG_REMOVE) Slog.d(TAG, “Deleting system app”);
- removeUser = user.getIdentifier();
- appId = ps.appId;
- mSettings.writePackageRestrictionsLPr(removeUser);
- }
- }
- }
- 。。。。。。
- if (dataOnly) {
- // Delete application data first,先删除应用的数据
- if (DEBUG_REMOVE) Slog.d(TAG, “Removing package data only”);
- removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
- return true;
- }
- boolean ret = false;
- if (isSystemApp(ps)) {//删除系统应用
- if (DEBUG_REMOVE) Slog.d(TAG, “Removing system package:” + ps.name);
- // When an updated system application is deleted we delete the existing resources as well and
- // fall back to existing code in system partition
- ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
- flags, outInfo, writeSettings);
- } else {//停止应用进程,删除文件
- if (DEBUG_REMOVE) Slog.d(TAG, “Removing non-system package:” + ps.name);
- // Kill application pre-emptively especially for apps on sd.
- killApplication(packageName, ps.appId, “uninstall pkg”);
- ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
- allUserHandles, perUserInstalled,
- outInfo, writeSettings);
- }
- return ret;
- }
deletePackageLI方法根据不同用户的安装情况来删除应用的apk文件和数据。
五、通过Intent查询组件
PMS在系统运行过程中,很重要的一项工作就是根据Intent来查询处理Intent的组件信息。处理Intent查询的接口如下:
- queryIntentActivities():查询处理Intent的Activity列表。
- queryIntentServices():查询处理Intent的Service列表。
- queryIntentReceivers():查询处理Intent的Receiver列表。
- queryIntentConentProviders():查询处理Intent的ContentProvider列表。
系统中响应某个Intent的组件可能有多个,因此,这些接口返回的是列表。查询到的组件信息都是用类ResolverInfo来表示的。Android定义了ResolveInfo类来表示所有组件。 以queryIntentActivities()为例分析查询过程。
[java]
view plain
copy
- public List<ResolveInfo> queryIntentActivities(Intent intent,
- String resolvedType, int flags, int userId) {
- if (!sUserManager.exists(userId)) return Collections.emptyList();//检查调用接口的用户的权限
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, “query intent activities”);
- ComponentName comp = intent.getComponent();
- if (comp == null) {
- if (intent.getSelector() != null) {
- intent = intent.getSelector();
- comp = intent.getComponent();
- }
- }
- if (comp != null) {//如果Intent中已经指定了模块和组件名称,则只会有一个匹配
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- final ActivityInfo ai = getActivityInfo(comp, flags, userId);//通过模块信息得到ActivityInfo
- if (ai != null) {
- final ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = ai;
- list.add(ri);
- }
- return list;
- }
- // reader
- synchronized (mPackages) {
- final String pkgName = intent.getPackage();
- if (pkgName == null) {//如果intent中没有包名,则在系统所有包中查找
- List<CrossProfileIntentFilter> matchingFilters =
- getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);//匹配所有的IntertFilter
- // Check for results that need to skip the current profile.首先检查带有SKIP_CURRENT_PROFILE标志的filter
- ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
- resolvedType, flags, userId);
- if (resolveInfo != null) {
- List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
- result.add(resolveInfo);
- return result;
- }
- // Check for cross profile results.
- resolveInfo = queryCrossProfileIntents(
- matchingFilters, intent, resolvedType, flags, userId);
- // Check for results in the current profile.在当前的profile下查找
- List<ResolveInfo> result = mActivities.queryIntent(
- intent, resolvedType, flags, userId);
- if (resolveInfo != null) {
- result.add(resolveInfo);
- Collections.sort(result, mResolvePrioritySorter);
- }
- return result;
- }
- final PackageParser.Package pkg = mPackages.get(pkgName);
- if (pkg != null) {//如果Intent中有包名,则在指定的包中查找
- return mActivities.queryIntentForPackage(intent, resolvedType, flags,
- pkg.activities, userId);
- }
- return new ArrayList<ResolveInfo>();
- }
- }
queryIntentActivities()方法会根据Intent中的信息来分别处理。如果Intent中有包名和Activity的信息,在调用getActivityInfo()直接返回ActivityInfo。如果只有包名,调用queryIntentForPackage方法在指定的包中查找Activity。如果包名也没有,调用queryIntent()方法来搜索所有安装包。