当前位置:   article > 正文

Android Framework 包管理子系统(03)应用安装_framework adb install

framework adb install

该系列文章总纲链接:专题分纲目录 Android Framework 包管理子系统


本章关键点总结 & 说明:

导图是不断迭代的,这里主要关注➕ PkgMS安装应用部分。主要是三个步骤:从执行adb install 到复制文件,再到装载文件,最后到安装成功。

PackagerInstallerService特殊说明:PackagerInstallerService(PkgMIS)是android5.0中新加入的服务,一般通过PackagerInstallerService来分配一个SessinId,这个系统唯一的ID代表一次安装过程,如果一个应用的安装被中断了,比如设备重启,那么也可以通过这个ID来继续安装。Session的创建如下所示:

  1. public int createSession(SessionParams params, String installerPackageName, int userId) {
  2. try {
  3. return createSessionInternal(params, installerPackageName, userId);
  4. } catch (IOException e) {
  5. throw ExceptionUtils.wrap(e);
  6. }
  7. }

该方法会返回个系统唯一值作为SessionID,如果希望再次使用Session,可以通过接口openSession打开,代码实现如下:

  1. public IPackageInstallerSession openSession(int sessionId) {
  2. try {
  3. return openSessionInternal(sessionId);
  4. } catch (IOException e) {
  5. throw ExceptionUtils.wrap(e);
  6. }
  7. }

这里将返回一个IPackageInstallerSession(PackageInstallerSession的IBinder对象),在PackagerManagerService中用变量mSession来存所有的PackageInstallerSession对象。这些PackageInstallerSession对象保存了应用安装的相关数据,比如安装路径、安装进度等。。。

1 安装应用程序(从 adb install 到PkgMS)

一般我们会使用adb install 来安装应用,因此这里就从adb install开始分析,adb命令,install参数。直接看adb命令 处理install参数的代码,如下所示:

  1. int adb_commandline(int argc, char **argv)
  2. {
  3. char buf[4096];
  4. //...
  5. if (!strcmp(argv[0], "install")) {
  6. if (argc < 2) return usage();
  7. return install_app(ttype, serial, argc, argv);
  8. }
  9. //...
  10. if (!strcmp(argv[0], "uninstall")) {
  11. if (argc < 2) return usage();
  12. return uninstall_app(ttype, serial, argc, argv);
  13. }
  14. //...
  15. usage();
  16. return 1;
  17. }

这里继续分析install_app实现,代码如下:

  1. int install_app(transport_type transport, char* serial, int argc, char** argv)
  2. {
  3. //这里需要设置复制目标的目录,如果安装在内部存储中,则目标目录为/data/local/tmp。
  4. static const char *const DATA_DEST = "/data/local/tmp/%s";
  5. //如果安装在SD卡上,则目标目录为/sdcard/tmp。
  6. static const char *const SD_DEST = "/sdcard/tmp/%s";
  7. //...
  8. for (i = 1; i < argc; i++) {
  9. if (!strcmp(argv[i], "-s")) {
  10. where = SD_DEST; //-s参数指明该APK安装到SD卡上
  11. }
  12. }
  13. //...
  14. char* apk_file = argv[last_apk];
  15. char apk_dest[PATH_MAX];
  16. snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
  17. //将此APK传送到手机的目标路径
  18. int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
  19. if (err) {
  20. goto cleanup_apk;
  21. } else {
  22. argv[last_apk] = apk_dest; /* destination name, not source location */
  23. }
  24. //执行pm命令
  25. pm_command(transport, serial, argc, argv);
  26. cleanup_apk:
  27. //手机中执行shell rm 命令,删除刚才传送过去的目标APK文件
  28. delete_file(transport, serial, apk_dest);
  29. return err;
  30. }

这里关注pm_command方法,代码如下:

  1. static int pm_command(transport_type transport, char* serial,
  2. int argc, char** argv)
  3. {
  4. char buf[4096];
  5. snprintf(buf, sizeof(buf), "shell:pm");
  6. while(argc-- > 0) {
  7. char *quoted = escape_arg(*argv++);
  8. strncat(buf, " ", sizeof(buf) - 1);
  9. strncat(buf, quoted, sizeof(buf) - 1);
  10. free(quoted);
  11. }
  12. send_shellcommand(transport, serial, buf);
  13. return 0;
  14. }

这里调用了send_shellcommand 发送"shell:pm install 参数"给手机端的adbd,这里继续分析pm命令,pm是脚本文件,构成如下:

  1. # Script to start "pm" on the device,which has a very rudimentary
  2. # shell.
  3. #
  4. base=/system
  5. export CLASSPATH=$base/frameworks/pm.jar
  6. exec app_process $base/bincom.android.commands.pm.Pm "$@"

在编译system镜像时,Android.mk中会将该脚本复制到system/bin目录下。从pm脚本的内容来看,它就是通过app_process执行pm.jar包的main函数。pm的main函数实现如下:

  1. public static void main(String[] args) {
  2. int exitCode = 1;
  3. exitCode = new Pm().run(args);
  4. //...
  5. System.exit(exitCode);
  6. }

这里的run方法实现如下:

  1. public int run(String[] args) throws IOException, RemoteException {
  2. //...
  3. //获取UserM 和 PkgMS的binder客户端
  4. mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
  5. mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
  6. //...
  7. mInstaller = mPm.getPackageInstaller();
  8. //...
  9. //处理其他命令,这里仅考虑install的处理
  10. if ("install".equals(op)) {
  11. return runInstall();
  12. }
  13. //...
  14. }

这里仅仅关注install部分相关代码,runInstall代码实现如下:

  1. private int runInstall() {
  2. int installFlags = 0;
  3. //...
  4. while ((opt=nextOption()) != null) {
  5. if (opt.equals("-l")) {
  6. installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
  7. } else if (opt.equals("-r")) {
  8. installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
  9. //...各种参数解析
  10. } else {
  11. System.err.println("Error: Unknown option: " + opt);
  12. return 1;
  13. }
  14. }
  15. //...
  16. //获取Verification Package的文件位置
  17. final String verificationFilePath = nextArg();
  18. if (verificationFilePath != null) {
  19. System.err.println("\tver: " + verificationFilePath);
  20. verificationURI = Uri.fromFile(new File(verificationFilePath));
  21. } else {
  22. verificationURI = null;
  23. }
  24. //创建PackageInstallObserver,用于接收PkgMS的安装结果
  25. LocalPackageInstallObserver obs = new LocalPackageInstallObserver();
  26. try {
  27. VerificationParams verificationParams = new VerificationParams(verificationURI,
  28. originatingURI, referrerURI, VerificationParams.NO_UID, null);
  29. //这里调用PkgMS来安装应用程序
  30. mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,
  31. installerPackageName, verificationParams, abi, userId);
  32. synchronized (obs) {
  33. while (!obs.finished) {
  34. try {
  35. obs.wait();//等待安装结果
  36. } catch (InterruptedException e) {
  37. //...
  38. }
  39. }
  40. //...
  41. }
  42. } catch (RemoteException e) {
  43. //...
  44. }
  45. }

这里调用了mPm.installPackageAsUser方法来处理“安装”,从 adb install 到PkgMS到此分析结束,接下来从这里开始便正式进入PkgMS来安装应用程序。

同时这里介绍另一种调用方式,给指定用户安装应用,安装应用程序也可以通过调用installPackage来实现,代码如下:

  1. public void installPackage(String originPath, IPackageInstallObserver2 observer,
  2. int installFlags, String installerPackageName, VerificationParams verificationParams,
  3. String packageAbiOverride) {
  4. installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
  5. packageAbiOverride, UserHandle.getCallingUserId());
  6. }

这里实际上也是调用了installPackageAsUser方法。因此后面的安装应用程序步骤会从installPackageAsUser开始分析。

2 安装应用程序(复制文件)

2.1 流程分析

从installPackageAsUser开始分析 安装应用程序的步骤,代码如下所示:

  1. public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
  2. int installFlags, String installerPackageName, VerificationParams verificationParams,
  3. String packageAbiOverride, int userId) {
  4. //检查调用进程的权限
  5. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
  6. //检查调用进程的用户是否有安装权限
  7. final int callingUid = Binder.getCallingUid();
  8. enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
  9. //检查用户是否被限制 安装应用
  10. if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
  11. try {
  12. if (observer != null) {
  13. //用户被限制,通知给监听者
  14. observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
  15. }
  16. } catch (RemoteException re) {
  17. }
  18. return;
  19. }
  20. if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
  21. installFlags |= PackageManager.INSTALL_FROM_ADB;
  22. } else {
  23. installFlags &= ~PackageManager.INSTALL_FROM_ADB;
  24. installFlags &= ~PackageManager.INSTALL_ALL_USERS;
  25. }
  26. UserHandle user;
  27. //如果有INSTALL_ALL_USERS标志,则给所有用户安装
  28. if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
  29. user = UserHandle.ALL;
  30. } else {
  31. user = new UserHandle(userId);
  32. }
  33. verificationParams.setInstallerUid(callingUid);
  34. final File originFile = new File(originPath);
  35. final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
  36. //保存参数到InstallParams对象
  37. final Message msg = mHandler.obtainMessage(INIT_COPY);
  38. msg.obj = new InstallParams(origin, observer, installFlags,
  39. installerPackageName, verificationParams, user, packageAbiOverride);
  40. mHandler.sendMessage(msg);//发送消息
  41. }

这里最后把调用的参数Installarams对象中,然后发送INIT_COPY消息。mHandler被绑定到另外一个工作线程(借助ThreadHandler对象的Looper)中,所以该INIT_COPY消息也将在那个工作线程中进行处理。接下来看handleMessage如何处理消息,代码如下:

  1. public void handleMessage(Message msg) {
  2. try {
  3. doHandleMessage(msg);
  4. } finally {
  5. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  6. }
  7. }

继续分析doHandleMessage,这里只关注INIT_COPY相关处理,代码如下:

  1. case INIT_COPY: {
  2. HandlerParams params = (HandlerParams) msg.obj;
  3. int idx = mPendingInstalls.size();
  4. if (!mBound) {
  5. //绑定defaultContainerService服务
  6. if (!connectToService()) {
  7. //错误处理
  8. } else {
  9. //连接成功,把安装信息保存到mPendingInstalls
  10. mPendingInstalls.add(idx, params);
  11. }
  12. } else {
  13. //插入安装信息
  14. mPendingInstalls.add(idx, params);
  15. //如果安装请求队列之前的状态为空,则表明要启动安装
  16. if (idx == 0) {
  17. mHandler.sendEmptyMessage(MCS_BOUND);
  18. }
  19. }
  20. break;
  21. }

这里有一个前提,成功启动了DefaultContainerService(简称DCS)且idx为零,所以这是PkgMS首次处理安装请求,即将要处理MCS_BOUND消息。继续分析MCS_BOUND的处理,代码如下:

  1. case MCS_BOUND: {
  2. if (msg.obj != null) {
  3. mContainerService = (IMediaContainerService) msg.obj;
  4. }
  5. if (mContainerService == null) {
  6. //错误处理
  7. } else if (mPendingInstalls.size() > 0) {
  8. HandlerParams params = mPendingInstalls.get(0);
  9. if (params != null) {
  10. if (params.startCopy()) {//执行安装
  11. if (mPendingInstalls.size() > 0) {
  12. //工作完成,删除第一项
  13. mPendingInstalls.remove(0);
  14. }
  15. if (mPendingInstalls.size() == 0) {
  16. if (mBound) {
  17. //安装请求都处理完了,则需要和Service断绝联系,
  18. //通过发送MSC_UNB消息处理断交请求
  19. removeMessages(MCS_UNBIND);
  20. Message ubmsg = obtainMessage(MCS_UNBIND);
  21. sendMessageDelayed(ubmsg, 10000);
  22. }
  23. } else {
  24. //还有未处理的请求,则继续发送MCS_BOUND
  25. mHandler.sendEmptyMessage(MCS_BOUND);
  26. }
  27. }
  28. }
  29. }
  30. break;
  31. }

这里先分析MCS_UNBIND的处理流程,代码如下所示:

  1. case MCS_UNBIND: {
  2. if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
  3. if (mBound) {
  4. disconnectService();
  5. }
  6. } else if (mPendingInstalls.size() > 0) {
  7. mHandler.sendEmptyMessage(MCS_BOUND);
  8. }
  9. break;
  10. }

可以看到,如果没有请求则与服务断开联系,只要还有请求,就会继续发送MCS_BOUND消息。接下来继续分析startCopy,代码实现如下:

  1. final boolean startCopy() {
  2. boolean res;
  3. try {
  4. if (++mRetries > MAX_RETRIES) {
  5. mHandler.sendEmptyMessage(MCS_GIVE_UP);
  6. handleServiceError();
  7. return false;
  8. } else {
  9. handleStartCopy();//调用派生类InstallParams的handleStartCopy函数
  10. res = true;
  11. }
  12. } catch (RemoteException e) {
  13. mHandler.sendEmptyMessage(MCS_RECONNECT);
  14. res = false;
  15. }
  16. //调用派生类InstallParams的handleReturnCode,返回处理结果
  17. handleReturnCode();
  18. return res;
  19. }

这里继续分析关键方法InstallParams类的handleStartCopy,代码如下:

  1. public void handleStartCopy() throws RemoteException {
  2. //...
  3. if (onInt && onSd) {
  4. // Check if both bits are set
  5. ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
  6. } else {
  7. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
  8. packageAbiOverride);
  9. if (!origin.staged && pkgLite.recommendedInstallLocation
  10. == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
  11. //如果安装空间不够,释放cache空间
  12. final StorageManager storage = StorageManager.from(mContext);
  13. final long lowThreshold = storage.getStorageLowBytes(
  14. Environment.getDataDirectory());
  15. final long sizeBytes = mContainerService.calculateInstalledSize(
  16. origin.resolvedPath, isForwardLocked(), packageAbiOverride);
  17. if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) {
  18. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
  19. installFlags, packageAbiOverride);
  20. }
  21. if (pkgLite.recommendedInstallLocation
  22. == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
  23. pkgLite.recommendedInstallLocation
  24. = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
  25. }
  26. }
  27. }
  28. //...
  29. //创建InstallArgs对象,如果应用要求安装在SD卡或forward lock的应用
  30. //则创建AsecInstallArgs,否则创建FileInstallArgs
  31. final InstallArgs args = createInstallArgs(this);
  32. mArgs = args;
  33. if (ret == PackageManager.INSTALL_SUCCEEDED) {
  34. //...
  35. final int requiredUid = mRequiredVerifierPackage == null ? -1
  36. : getPackageUid(mRequiredVerifierPackage, userIdentifier);
  37. if (!origin.existing && requiredUid != -1
  38. && isVerificationEnabled(userIdentifier, installFlags)) {
  39. //...校验相关
  40. } else {//无需校验则直接处理
  41. ret = args.copyApk(mContainerService, true);
  42. }
  43. }
  44. mRet = ret;
  45. }

这里关注无需校验环节的copyApk(依赖于args的类,这里只从FileInstallArgs类开始分析)方法实现,代码如下:

  1. int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
  2. if (origin.staged) {
  3. codeFile = origin.file;
  4. resourceFile = origin.file;
  5. return PackageManager.INSTALL_SUCCEEDED;
  6. }
  7. try {
  8. //在data/app下生成临时文件
  9. final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
  10. codeFile = tempDir;
  11. resourceFile = tempDir;
  12. } catch (IOException e) {
  13. return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
  14. }
  15. final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
  16. //为临时文件创建文件描述符ParcelFileDescriptor,能够通过Binder传递
  17. @Override
  18. public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
  19. if (!FileUtils.isValidExtFilename(name)) {
  20. throw new IllegalArgumentException("Invalid filename: " + name);
  21. }
  22. try {
  23. final File file = new File(codeFile, name);
  24. final FileDescriptor fd = Os.open(file.getAbsolutePath(),
  25. O_RDWR | O_CREAT, 0644);
  26. Os.chmod(file.getAbsolutePath(), 0644);
  27. return new ParcelFileDescriptor(fd);
  28. } catch (ErrnoException e) {
  29. throw new RemoteException("Failed to open: " + e.getMessage());
  30. }
  31. }
  32. };
  33. int ret = PackageManager.INSTALL_SUCCEEDED;
  34. //复制文件
  35. ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
  36. if (ret != PackageManager.INSTALL_SUCCEEDED) {
  37. return ret;
  38. }
  39. //安装系统自带的native动态库
  40. final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
  41. NativeLibraryHelper.Handle handle = null;
  42. try {
  43. handle = NativeLibraryHelper.Handle.create(codeFile);
  44. ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
  45. abiOverride);
  46. } catch (IOException e) {
  47. ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
  48. } finally {
  49. IoUtils.closeQuietly(handle);
  50. }
  51. return ret;
  52. }

至此,安装的第一部份工作完成,应用安装到/data/app目录下。

2.2 关键类说明

HandlerParams和InstallArgs介绍,关系如下所示:

HandlerParams和InstallArgs均为抽象类。HandlerParams有三个子类:InstallParams、MoveParams和MeasureParams:

  1. InstallParams 处理APK的安装。
  2. MoveParams 处理某个已安装APK的搬家请求(例如从内部存储移动到SD卡上)。
  3. MeasureParams 查询某个已安装的APK占据存储空间的大小(例如在设置程序中得到的某个APK使用的缓存文件的大小)。

对于InstallParams来说,它还有两个伴儿,即InstallArgs的派生类FileInstallArgs和AsecInstallArgs。FileInstallArgs针对的是安装在内部存储的APK,而AsecInstallArgs针对的是那些安装在SD卡上的APK。(整个流程的分析,包括后面,都是针对FileInstallArgs来做,AsecInstallArgs分析方式类似)

3 应用安装第二阶段:装载应用

本阶段是将应用格式转换成oat格式,为应用创建数据目录,最后把应用的信息装载到PkgMS的数据结构中,在前面startCopy函数中最后调用了handleReturnCode方法,代码如下:

  1. void handleReturnCode() {
  2. if (mArgs != null) {
  3. processPendingInstall(mArgs, mRet);
  4. }
  5. }

继续分析processPendingInstall,代码实现如下:

  1. private void processPendingInstall(final InstallArgs args, final int currentStatus) {
  2. // Queue up an async operation since the package installation may take a little while.
  3. mHandler.post(new Runnable() {
  4. public void run() {
  5. mHandler.removeCallbacks(this);//防止重复调用
  6. PackageInstalledInfo res = new PackageInstalledInfo();
  7. res.returnCode = currentStatus;
  8. res.uid = -1;
  9. res.pkg = null;
  10. res.removedInfo = new PackageRemovedInfo();
  11. //如果应用安装成功,则装载安装的应用
  12. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  13. //InstallArgs的doPreInstall函数
  14. args.doPreInstall(res.returnCode);
  15. synchronized (mInstallLock) {
  16. //关键函数,进行APK安装
  17. installPackageLI(args, res);
  18. }
  19. //FileInstallArgs的doPostInstall函数
  20. args.doPostInstall(res.returnCode, res.uid);
  21. }
  22. //执行备份相关代码(通过BackupManagerService来备份处理)...
  23. if (!doRestore) {
  24. //发送POST_INSTALL消息
  25. Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
  26. mHandler.sendMessage(msg);
  27. }
  28. }
  29. });
  30. }

该方法总结如下:

  1. 这里的InstallArgs的doPreInstall函数在本例中是FileInstallArgs的doPreInstall函数。
  2. 调用PkgMS的installPackageLI函数进行APK安装,接下来将深度分析该方法。
  3. 这里的InstallArgs的doPostInstall函数在本例中是FileInstallArgs的doPostInstall函数。
  4. 此时,该APK已经安装完成(不论失败还是成功),继续向mHandler抛送一个POST_INSTALL消息,该消息携带一个token,通过它可从mRunningInstalls数组中取得一个PostInstallData对象。后面也将继续分析handler对POST_INSTALL的处理流程。

接下来将针对{步骤2}的installPackageLI和{步骤4}的handler消息处理进行详细分析。

@1 installPackageLI实现

  1. private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
  2. //...
  3. final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
  4. | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
  5. | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
  6. //创建apk文件的解析器
  7. PackageParser pp = new PackageParser();
  8. pp.setSeparateProcesses(mSeparateProcesses);
  9. pp.setDisplayMetrics(mMetrics);
  10. final PackageParser.Package pkg;
  11. try {
  12. //解析apk文件
  13. pkg = pp.parsePackage(tmpPackageFile, parseFlags);
  14. } catch (PackageParserException e) {
  15. res.setError("Failed parse during installPackageLI", e);
  16. return;
  17. }
  18. //收集应用的签名
  19. try {
  20. pp.collectCertificates(pkg, parseFlags);
  21. pp.collectManifestDigest(pkg);
  22. } catch (PackageParserException e) {
  23. res.setError("Failed collect during installPackageLI", e);
  24. return;
  25. }
  26. //...
  27. pp = null;
  28. String oldCodePath = null;
  29. boolean systemApp = false;
  30. synchronized (mPackages) {
  31. //升级判定及相关处理
  32. int N = pkg.permissions.size();
  33. //permission相关处理
  34. }
  35. //有系统标志的应用要求装在sd卡上,报错退出
  36. if (systemApp && onSd) {
  37. res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
  38. "Cannot install updates to system apps on sdcard");
  39. return;
  40. }
  41. //如果更名失败,则退出
  42. if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
  43. res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
  44. return;
  45. }
  46. if (replace) {
  47. //如果安装的是升级包
  48. replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
  49. installerPackageName, res);
  50. } else {
  51. //如果是新应用
  52. installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
  53. args.user, installerPackageName, res);
  54. }
  55. synchronized (mPackages) {
  56. final PackageSetting ps = mSettings.mPackages.get(pkgName);
  57. if (ps != null) {
  58. res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
  59. }
  60. }
  61. }

installPackageLI首先解析了安装的应用文件,得到解析的结果后,主要是判断新安装应用是否和应用系统中已安装应用构成升级关系,是则调用replacePackageLI来处理,否则就用installNewPackageLI来处理。

@2 POST_INSTALL消息处理

相关代码如下:

  1. case POST_INSTALL: {
  2. PostInstallData data = mRunningInstalls.get(msg.arg1);
  3. mRunningInstalls.delete(msg.arg1);
  4. boolean deleteOld = false;
  5. if (data != null) {
  6. InstallArgs args = data.args;
  7. PackageInstalledInfo res = data.res;
  8. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  9. res.removedInfo.sendBroadcast(false, true, false);
  10. Bundle extras = new Bundle(1);
  11. extras.putInt(Intent.EXTRA_UID, res.uid);
  12. //...
  13. //发送广播ACTION_PACKAGE_ADDED
  14. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
  15. res.pkg.applicationInfo.packageName,
  16. extras, null, null, firstUsers);
  17. final boolean update = res.removedInfo.removedPackage != null;
  18. if (update) {
  19. extras.putBoolean(Intent.EXTRA_REPLACING, true);
  20. }
  21. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
  22. res.pkg.applicationInfo.packageName,
  23. extras, null, null, updateUsers);
  24. if (update) {
  25. //如果是升级包,则发送更多的广播
  26. sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
  27. res.pkg.applicationInfo.packageName,
  28. extras, null, null, updateUsers);
  29. sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
  30. null, null,
  31. res.pkg.applicationInfo.packageName, null, updateUsers);
  32. //如果是forward lock的应用,或者安装在sd卡上的应用,发送广播
  33. if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {
  34. int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
  35. ArrayList<String> pkgList = new ArrayList<String>(1);
  36. pkgList.add(res.pkg.applicationInfo.packageName);
  37. sendResourcesChangedBroadcast(true, true,
  38. pkgList,uidArray, null);
  39. }
  40. }
  41. if (res.removedInfo.args != null) {
  42. deleteOld = true;
  43. }
  44. }
  45. //...
  46. if (args.observer != null) {
  47. try {//通知调用者 安装的结果
  48. Bundle extras = extrasForInstallResult(res);
  49. args.observer.onPackageInstalled(res.name, res.returnCode,
  50. res.returnMsg, extras);
  51. } catch (RemoteException e) {
  52. Slog.i(TAG, "Observer no longer exists.");
  53. }
  54. }
  55. }
  56. } break;

整个消息处理主要是发送广播,应用安装成功后通知其他的应用开始处理,比如Launcher中需要添加的图标等。。。最后通过回调函数通知 安装者 安装的结果。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/199112
推荐阅读
相关标签
  

闽ICP备14008679号