{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/",
  "atlas": "https://www.pystone.net/?node=android-apk-install-uninstall-mechanism#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism.md",
  "context": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:android-apk-install-uninstall-mechanism",
  "slug": "android-apk-install-uninstall-mechanism",
  "title": "Android APK安装与卸载机制（转载）",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "Android APK安装与卸载机制（转载） Android APK安装与卸载机制 Jenney TEN的博客 程序员ITS404",
  "contentRole": "unspecified",
  "sourceMetadata": {
    "reference": "https://www.its404.com/article/zhangxu0922/51941070"
  },
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "updatedAt": "2024-01-14T08:55:21.000005Z",
  "contentHash": "aa462a3cd99850078ab2f964bdb27e20ff2214641b91e4f4daae387eafaf9601",
  "assets": [],
  "headings": [
    {
      "depth": 1,
      "text": "Android APK安装与卸载机制（转载）",
      "anchor": "android-apk安装与卸载机制转载",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#android-apk%E5%AE%89%E8%A3%85%E4%B8%8E%E5%8D%B8%E8%BD%BD%E6%9C%BA%E5%88%B6%E8%BD%AC%E8%BD%BD"
    },
    {
      "depth": 2,
      "text": "Android APK安装与卸载机制 JenneyTEN的博客-程序员ITS404",
      "anchor": "android-apk安装与卸载机制-jenneyten的博客-程序员its404",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#android-apk%E5%AE%89%E8%A3%85%E4%B8%8E%E5%8D%B8%E8%BD%BD%E6%9C%BA%E5%88%B6-jenneyten%E7%9A%84%E5%8D%9A%E5%AE%A2-%E7%A8%8B%E5%BA%8F%E5%91%98its404"
    },
    {
      "depth": 2,
      "text": "1. APK安装卸载方法及原理浅析",
      "anchor": "1-apk安装卸载方法及原理浅析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#1-apk%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E6%96%B9%E6%B3%95%E5%8F%8A%E5%8E%9F%E7%90%86%E6%B5%85%E6%9E%90"
    },
    {
      "depth": 3,
      "text": "1.1 APK安装方式",
      "anchor": "11-apk安装方式",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#11-apk%E5%AE%89%E8%A3%85%E6%96%B9%E5%BC%8F"
    },
    {
      "depth": 3,
      "text": "1.2 APK安装、卸载原理浅析",
      "anchor": "12-apk安装卸载原理浅析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#12-apk%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E5%8E%9F%E7%90%86%E6%B5%85%E6%9E%90"
    },
    {
      "depth": 3,
      "text": "1.3 APK几种安装方式异同点",
      "anchor": "13-apk几种安装方式异同点",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#13-apk%E5%87%A0%E7%A7%8D%E5%AE%89%E8%A3%85%E6%96%B9%E5%BC%8F%E5%BC%82%E5%90%8C%E7%82%B9"
    },
    {
      "depth": 2,
      "text": "2. PMS安装APK的过程解析",
      "anchor": "2-pms安装apk的过程解析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#2-pms%E5%AE%89%E8%A3%85apk%E7%9A%84%E8%BF%87%E7%A8%8B%E8%A7%A3%E6%9E%90"
    },
    {
      "depth": 3,
      "text": "2.1 扫描安装过程解析",
      "anchor": "21-扫描安装过程解析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#21-%E6%89%AB%E6%8F%8F%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E8%A7%A3%E6%9E%90"
    },
    {
      "depth": 3,
      "text": "2.2 adb命令安装过程解析",
      "anchor": "22-adb命令安装过程解析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#22-adb%E5%91%BD%E4%BB%A4%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E8%A7%A3%E6%9E%90"
    },
    {
      "depth": 4,
      "text": "2.2.1 adb install命令",
      "anchor": "221-adb-install命令",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#221-adb-install%E5%91%BD%E4%BB%A4"
    },
    {
      "depth": 3,
      "text": "2.2.2 adb shell pm命令",
      "anchor": "222-adb-shell-pm命令",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#222-adb-shell-pm%E5%91%BD%E4%BB%A4"
    },
    {
      "depth": 3,
      "text": "2.3 PMS中相关代码分析",
      "anchor": "23-pms中相关代码分析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#23-pms%E4%B8%AD%E7%9B%B8%E5%85%B3%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90"
    },
    {
      "depth": 2,
      "text": "3. APK安装核心函数ScanPackageDirtyLI函数分析",
      "anchor": "3-apk安装核心函数scanpackagedirtyli函数分析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#3-apk%E5%AE%89%E8%A3%85%E6%A0%B8%E5%BF%83%E5%87%BD%E6%95%B0scanpackagedirtyli%E5%87%BD%E6%95%B0%E5%88%86%E6%9E%90"
    },
    {
      "depth": 3,
      "text": "3.2 createDataDirsLI分析",
      "anchor": "32-createdatadirsli分析",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#32-createdatadirsli%E5%88%86%E6%9E%90"
    },
    {
      "depth": 3,
      "text": "3.3 Installer介绍",
      "anchor": "33-installer介绍",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#33-installer%E4%BB%8B%E7%BB%8D"
    },
    {
      "depth": 3,
      "text": "3.4 Installed介绍",
      "anchor": "34-installed介绍",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#34-installed%E4%BB%8B%E7%BB%8D"
    },
    {
      "depth": 2,
      "text": "4. APK的卸载",
      "anchor": "4-apk的卸载",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#4-apk%E7%9A%84%E5%8D%B8%E8%BD%BD"
    },
    {
      "depth": 2,
      "text": "5. 待完成的任务",
      "anchor": "5-待完成的任务",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#5-%E5%BE%85%E5%AE%8C%E6%88%90%E7%9A%84%E4%BB%BB%E5%8A%A1"
    },
    {
      "depth": 2,
      "text": "6.小结",
      "anchor": "6小结",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#6%E5%B0%8F%E7%BB%93"
    },
    {
      "depth": 2,
      "text": "7.参考文献",
      "anchor": "7参考文献",
      "citation": "https://www.pystone.net/notes/android-apk-install-uninstall-mechanism/#7%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:application-and-cloud-engineering",
      "title": "应用开发与云端工程",
      "url": "https://www.pystone.net/notes/application-and-cloud-engineering/",
      "atlas": "https://www.pystone.net/?node=application-and-cloud-engineering#knowledge-atlas",
      "label": "应用开发与云端工程",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "Android开发中的“Android APK安装与卸载机制（转载）”导航项",
      "citation": "https://www.pystone.net/notes/application-and-cloud-engineering/#android%E5%BC%80%E5%8F%91"
    }
  ],
  "contentMarkdown": "# Android APK安装与卸载机制（转载）\n## Android APK安装与卸载机制_ Jenney_TEN的博客-程序员ITS404\n\n技术标签：[app](https://www.its404.com/searchArticle?qc=app&page=1)[frameworks](https://www.its404.com/searchArticle?qc=frameworks&page=1)[apk](https://www.its404.com/searchArticle?qc=apk&page=1)[积累](https://www.its404.com/searchArticle?qc=%E7%A7%AF%E7%B4%AF&page=1)\n\n\n本文主要介绍Android系统如何实现APK安装、卸载、更新等操作。主要内容包括以下内容：\n\n1. 安装和卸载APK的方法有哪些，每种方法实现的原理是什么？\n2. APK安装和卸载过程中，系统数据发生了哪些变化？\n3. Android App端常用的Package Manager使用方法简介。\n注：本文是在本人阅读Android的设计与实现I、深入理解Android卷II、以及网络中关于Android安装方式的基础上完成的。本人的主要工作在于阅读相关部分的Android源代码，并制作相应代码调用的时序图；尝试将所阅读的文章中的安装方法付诸实施。\n\n\n## 1. APK安装卸载方法及原理浅析\n\n### 1.1 APK安装方式\n\n常见的APK安装方式有以下几种：\n\n\n| 安装方式 | 触发时机 | 面向的用户类型 |\n| --- | --- | --- |\n| 系统自带和厂商预装 | 系统首次启动 | System Designer |\n| adb命令安装 | 使用adb push命令 | Programmer |\n| adb命令安装 | 使用adb (shell pm) install命令 | Programmer |\n| 网络下载应用安装 | 下载完成之后安装 | User |\n| 第三方应用安装(PackageInstaller.apk等） | 通过SdCard中的APK安装 | User |\n\n\n### 1.2 APK安装、卸载原理浅析\n\nAndroid系统中，APK安装、卸载的原理，与Windows系统软件安装(具体原理参考[软件安装原理](https://wenku.baidu.com/view/18cb1b1cff00bed5b9f31d13.html)、[MSI文件简介](http://blog.csdn.net/femalelover/article/details/568876))的基本原理类似。\n\n- APK安装可以归结为以下几个过程：\n- APK卸载：将APK文件、data/data/pacakgeName/、dalvik-cache目录中相应的文件删除;并更新PMS中相应的数据结构。\n\n### 1.3 APK几种安装方式异同点\n\n1. 系统自带的应用以及厂商预装的应用等，在手机首次启动时，会通过扫描/system/app/、/system/framework/、/vendor/app/等目录下面的APK文件，完成安装；如果是Android的原生系统，或者cm等系统，则没有/vendor/app/目录。\n2. 通过adb push命令可以将APK文件推送到/system/app/、/system/framework/、/vendor/app/、/data/app/等目录下面，然后再次启动手机设备，便可以完成安装过程。具体命令如下： adb root adb push flyflow-release.apk /system/app adb reboot 使用该方式安装APK，具有以下特点：\n3. 使用adb install命令安装APK。常用的命令如下： adb install flyflow-release.apk adb shell pm install flyflow-release.apk 这两种命令最终都会调用Android端的/bin/pm的install命令完成安装。\n4. 网络应用下载安装APK之后，会调用PackageManager的installPackage(*)方法完成安装工作；该方法最终会调用PackageManagerService中的installPackage来完成APK安装。可通过以下形式实现验证： a) 将APK文件实现放入sdcard中； b) 设计一个Android InstallDemo，包含一个按钮，点击按钮便会调用installPackage方法进行安装。其中installPackage安装的文件为步骤a中的APK； 注意事项有：\n5. 使用PackageInstaller.apk进行安装时，其启动PackageInstallerActivity来完成安装包解析；在解析完成并得到用户的安装确认之后，启动 InstallAppProgress并调用安装接口pm.installPackage进行安装。（该方式未进行深入调研，道听途说）\n\n## 2. PMS安装APK的过程解析\n\n本节详细介绍APK的几种安装方式，主要包括开机扫描安装、adb install命令安装等。\n\n\n### 2.1 扫描安装过程解析\n\nAndroid设备在启动的过程中，会扫描本地安装的所有的App。整个扫描过程可以通过以下流程图来说明：扫描安装过程分析如下：\n\n1. 在PackageManagerService构造函数中，扫描各个APK目录之前会创建一个Settings对象mSettings。其中Settings类负责读取系统的配置信息，主要解析的文件有packages.xml、packages-stopped.xml等文件。会将解析的信息分别存入mPackages、mRenamedPackages、mDisableSysPackages等数据结构中。重要的函数调用有: mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),mSdkVersion, mOnlyCore);\n2. 开机启动时会以此扫描目录：/system/app、/system/framework、 /vendor/app、/data/app等。具体调用有：\n3. 扫描每个APK目录的核心代码如下： // scanDirLI(**) for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } try { scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK, scanFlags, currentTime, null); } catch (PackageManagerException e) { // exception process ..... }\n4. scanPackageLI(File scanFile,...)该函数负责完成APK的扫描工作，APK的扫描工作具体有PackageParser.parsePackage(*)完成。在扫描过程中，会解析AndroidManifiest.xml文件等信息，并将扫描结果存放在PackageParser.Package对象中。\n5. 在完成包的信息解析之后需要完成包信息同步工作,主要因为：scanPackageLI扫描到的APK可能是已经更名的包、disable的包、需要升级的包、已经安装并且签名冲突的包、被非系统级包替代系统包的情况，需要对这些情况一一处理，保证信息的正确性。\n6. 如果Package需要Rename或者Update则会进行签名比较，以防止签名不一致的情况；\n7. 最终会调用scanPackageLI（PackageParser.Package,....)函数完成实际的Package安装或更新操作。\n8. 在扫描过程中，Package的Rename、Update、Install操作都是由scanPackage(PackageParser,int,int,long,UserHandler)来完成.该函数会调用scanPackageDirtyLI(...)完成具体的操作。scanPackageDirtyLI函数在后续章节会分析。\n\n---\n\n\n### 2.2 adb命令安装过程解析\n\nAndroid adb的实现原理见[adb原理与adb常用命令](http://blog.csdn.net/eleven521/article/details/22747345)。在Console中输入adb的命令，最终会使用[android /platform/system/core/adb/commandline.c](https://android.googlesource.com/platform/system/core/+/4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53/adb/commandline.c)进行命令解析。\n\n\n#### 2.2.1 adb install命令\n\nadb命令的intall命令在commandline.c中对应的实现函数为install_app(....),该函数的代码有如下调用：\n\nif (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {\n\n/* file in place; tell the Package Manager to install it */\n\nargv[argc - 1] = to;\n\n/* destination name, not source location */\n\npm_command(transport, serial, argc, argv);\n\ndelete_file(transport, serial, to);\n\n}\n\npm_command(...)函数实现如下：\n\nstatic int pm_command(transport_type transport, char* serial,\n\nint argc, char** argv)\n\n{\n\nchar buf[4096];\n\nsnprintf(buf, sizeof(buf), shell:pm);\n\nwhile(argc-- 0) {\n\nchar *quoted;\n\nquoted = dupAndQuote (*argv++);\n\nstrncat(buf, , sizeof(buf)-1);\n\nstrncat(buf, quoted, sizeof(buf)-1);\n\nfree(quoted);\n\n}\n\nsend_shellcommand(transport, serial, buf);\n\nreturn 0;\n\n}\n\npm_command通过最终通过send_shellcommand(...)将数据发送到手机端的adbd守护进程中；adbd在收到PC的Console发来的数据之后，会启动一个Shell，然后执行pm。\n\n\n### 2.2.2 adb shell pm命令\n\nAndroid设备端pm命令位于/system/bin目录下，其是一个脚本，具体内容如下：\n\n#!/system/bin/sh\n\nbase=/system\n\nexport CLASSPATH=$base/framework/pm.jar\n\nexec app_process $base/bin com.android.commands.pm.Pm $@\n\n1. 从上面脚本可以看出，pm命令通过app_process执行pm.jar包的main函数;\n\n2. Android系统中常用的monkey、pm、am等脚本都是使用该方式来运行;\n\n3. pm.jar对应的类为com.android.commands.pm.Pm，具体的安装函数由runInstall来实现。该函数解析剩余的install命令参数，并最终调用以下代码完成安装：\n\n// Populate verificationURI, optionally present\n\nfinal String verificationFilePath = nextArg();\n\nif (verificationFilePath != null) {\n\nSystem.err.println(\\tver: + verificationFilePath);\n\nverificationURI = Uri.fromFile(new File(verificationFilePath));\n\n} else {\n\nverificationURI = null;\n\n}\n\n\nLocalPackageInstallObserver obs = new LocalPackageInstallObserver();\n\ntry {\n\nVerificationParams verificationParams = new VerificationParams(verificationURI,originatingURI,\n\nreferrerURI, VerificationParams.NO_UID, null);\n\n// 调用PMS完成安装\n\nmPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,\n\ninstallerPackageName, verificationParams, abi, userId);\n\n// 安装结果后续处理\n\n....\n\n} catch (RemoteException e) {\n\nSystem.err.println(e.toString());\n\nSystem.err.println(PM_NOT_RUNNING_ERR);\n\nreturn 1;\n\n}\n\n\n---\n\n\n### 2.3 PMS中相关代码分析\n\nadb安装命令最终调用PMS中的installPackageAsUser函数进行APK安装。整个过程的时序图如下图所示：安装APK的过程中具有以下特征：\n\n- installPackageAsUser函数检查客户端进程是否具有安装Package的权限，其中Shell和root进程都是具有该权限的。\n- installPackageAsUser函数会向PackageHandler发送一个INIT_COPY的消息，由PackageHandler来完成APK安装；\n- PackageHandler会调用InstallParms中的handleStartCopy()和handleReturnCode函数完成相应的操作。\n- 在handleStartCopy函数里完成的事情有：\n- 通过adb命令安装APK时，最终也是调用scanPackageDirLI函数完成APK安装。\n- 在该过程中，会判断是新安装一个APK还是覆盖更新安装APK。针对不同的情况会进行特殊的处理。\n- 在安装完成之后，processPendingInstall函数会想PackageHandler发送一个POST_INSTALL消息。然后在该消息的处理中，会根据APK的安装情况，发送相应的广播信息。\n\n## 3. APK安装核心函数ScanPackageDirtyLI函数分析\n\n从上述过程可以看出，不论是开机扫描安装APK，还是通过adb命令安装APK，最终都会调用scanPackageDirtyLI函数进行APK安装。该函数的流程图如下图所示：该函数完成的主要工作有：\n\n- 初始化Package的数据目录和资源目录；\n- 如果需要则更新已有的Package的共享代码库；\n- 如果安装时传递了签名信息，则验证签名信息的合法性；\n- 验证新安装的APK中的Provider是否与系统中现有的Provider有冲突，并进行相应的处理；\n- 如果新安装APK需要使用其他Package的权限，则进行相应处理；\n- 调用createDataDirsLI()安装APK；\n- 设置本地lib路径；\n- 安装成功之后将Package信息更新到PMS和Setting相应的数据结构中；\n- 设置APK安装时间；\n- 设置APK的Provider信息，将Provider添加到相应的数据结构中；\n- 设置权限组和权限信息；\n- 该函数的主要工作便是将安装的APK的信息添加到PMS中，比如讲Provider、Activity、Service、Receiver等组件信息添加到相应的数据结构中，以便其他函数能够查询到。\n- 在该函数中还对framework-res.apk进行特殊的信息处理。framework-res.apk中主要包含以下信息：\n\n---\n\n\n### 3.2 createDataDirsLI分析\n\n上个小节已经说明，scanPackageDirLI函数会调用createDataDirsLI的函数来完成安装。该函数主要做了两件事情：\n\n- 调用mInstaller.install()函数完成APK安装;\n- 调用mInstaller.createUserData()函数创建用户信息。 其中mInstaller是在PMS.main()函数中传递进来的Installer对象。该函数代码如下： private int createDataDirsLI(String packageName, int uid, String seinfo) { int[] users = sUserManager.getUserIds(); int res = mInstaller.install(packageName, uid, uid, seinfo); if (res 0) { return res; } for (int user : users) { if (user != 0) { res = mInstaller.createUserData(packageName, UserHandle.getUid(user, uid), user, seinfo); if (res 0) { return res; } } } return res; }\n\n---\n\n\n### 3.3 Installer介绍\n\n通过Installer类中install函数代码如下：\n\npublic int install(String name, int uid, int gid, String seinfo) {\n\nStringBuilder builder = new StringBuilder(install);\n\nbuilder.append( );\n\nbuilder.append(name);\n\nbuilder.append( );\n\nbuilder.append(uid);\n\nbuilder.append( );\n\nbuilder.append(gid);\n\nbuilder.append( );\n\nbuilder.append(seinfo != null ? seinfo : !);\n\nreturn mInstaller.execute(builder.toString());\n\n}\n\n分析得出以下结论： 1. Installer.install()函数和createUserData()进行完成了命令组装工作，在组装完命令之后，将命令传递给InstallerConnection处理。 通过分析InstallerConnection.java得到以下结论： 1. InstallerConnection连接一个名为Installd的服务 2. Install具体的命令有Installd完成。 其中InstallerConnnection.connect()函数代码如下：\n\nprivate boolean connect() {\n\nif (mSocket != null) {\n\nreturn true;\n\n}\n\nSlog.i(TAG, connecting...);\n\ntry {\n\nmSocket = new LocalSocket();\n\nLocalSocketAddress address = new LocalSocketAddress(installd,\n\nLocalSocketAddress.Namespace.RESERVED);\n\nmSocket.connect(address);\n\nmIn = mSocket.getInputStream();\n\nmOut = mSocket.getOutputStream();\n\n} catch (IOException ex) {\n\ndisconnect();\n\nreturn false;\n\n}\n\nreturn true;\n\n}\n\n\n---\n\n\n### 3.4 Installed介绍\n\nInstalld是一个native进程，该进程启动一个socket，然后处理来之Installer的命令。Installd的实现原理可以参考博文[Android安装服务installd源码分析](http://blog.csdn.net/yangwen123/article/details/11104397)。 installd源码位于[frameworks/base/cmds/installd](https://android.googlesource.com/platform/frameworks/base/+/742a67127366c376fdf188ff99ba30b27d3bf90c/cmds/installd)目录下，其中install操作对应的源代码在frameworks/base/cmds/installd/commands.c中，具体代码如下：\n\nint install(const char *pkgname, uid_t uid, gid_t gid)\n\n{\n\nchar pkgdir[PKG_PATH_MAX];//程序目录路径最长为256\n\nchar libdir[PKG_PATH_MAX];//程序lib路径最长为256\n\n//权限判断\n\nif ((uid AID_SYSTEM) || (gid AID_SYSTEM)) {\n\nALOGE(invalid uid/gid: %d %d\\n, uid, gid);\n\nreturn -1;\n\n}\n\n//组合应用程序安装目录pkgdir=/data/data/应用程序包名\n\nif (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {\n\nALOGE(cannot create package path\\n);\n\nreturn -1;\n\n}\n\n//组合应用程序库目录libdir=/data/data/应用程序包名/lib\n\nif (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {\n\nALOGE(cannot create package lib path\\n);\n\nreturn -1;\n\n}\n\n//创建目录pkgdir=/data/data/应用程序包名\n\nif (mkdir(pkgdir, 0751) 0) {\n\nALOGE(cannot create dir %s: %s\\n, pkgdir, strerror(errno));\n\nreturn -errno;\n\n}\n\n//修改/data/data/应用程序包名目录的权限\n\nif (chmod(pkgdir, 0751) 0) {\n\nALOGE(cannot chmod dir %s: %s\\n, pkgdir, strerror(errno));\n\nunlink(pkgdir);\n\nreturn -errno;\n\n}\n\n//创建目录libdir=/data/data/应用程序包名/lib\n\nif (mkdir(libdir, 0755) 0) {\n\nALOGE(cannot create dir %s: %s\\n, libdir, strerror(errno));\n\nunlink(pkgdir);\n\nreturn -errno;\n\n}\n\n//修改/data/data/应用程序包名/lib目录的权限\n\nif (chmod(libdir, 0755) 0) {\n\nALOGE(cannot chmod dir %s: %s\\n, libdir, strerror(errno));\n\nunlink(libdir);\n\nunlink(pkgdir);\n\nreturn -errno;\n\n}\n\n//修改/data/data/应用程序包名目录的所有权限\n\nif (chown(libdir, AID_SYSTEM, AID_SYSTEM) 0) {\n\nALOGE(cannot chown dir %s: %s\\n, libdir, strerror(errno));\n\nunlink(libdir);\n\nunlink(pkgdir);\n\nreturn -errno;\n\n}\n\n//修改/data/data/应用程序包名/lib目录的所有权限\n\nif (chown(pkgdir, uid, gid) 0) {\n\nALOGE(cannot chown dir %s: %s\\n, pkgdir, strerror(errno));\n\nunlink(libdir);\n\nunlink(pkgdir);\n\nreturn -errno;\n\n}\n\nreturn 0;\n\n}\n\n\n---\n\n\n## 4. APK的卸载\n\n从Installd的实现中，我们可以看到unInstall操作其实就是删除相应的数据文件和资源文件。unInstall的具体实现如下:\n\nint uninstall(const char *pkgname, uid_t persona)\n\n{\n\nchar pkgdir[PKG_PATH_MAX];\n\nif (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))\n\nreturn -1;\n\n/* delete contents AND directory, no exceptions */\n\nreturn delete_dir_contents(pkgdir, 1, NULL);\n\n}\n\n\n---\n\n\n## 5. 待完成的任务\n\n1. PackageInstaller.apk等第三方App如何实现APK安装；\n2. 如何重命名一个APK，以及更换APK的ICON；\n3. 通过adb push命令将APK安装包推送到/system/app能否实时触发APK安装；\n4. APK安装完成之后，是否能立即查询到该APK信息；卸载完成之后，是否可立即判断当前的包已经被卸载；\n5. 制作Demo完成APK安装，使用命令完成APK安装；\n6. 如何通过APK安装/卸载的广播进行相关编程；\n\n## 6.小结\n\n1. adb的实现机制\n2. Content Provider命名、自定义Permission命名等需要保证全局唯一；\n3. 安装、卸载完成会发送广播；\n4. Pm、monkey、Am脚本的实现机制；\n5. 可以通过adb push或者直接将APK放入到/system/app、/vendor/app完成预置操作；\n6. 如果遇到安装失败的情况，终极方案直接删除相应的文件，并重启手机；\n7. 一台PC最多同时连接16个device/emulator；\n8. /data/data//该文件的权限为751； /data/data//lib该目录的权限为755，说明每个App的lib是所有用户可读可运行的。\n\n## 7.参考文献\n\n1. 深入理解Android卷II\n2. Android的设计与实现卷I\n3. [In Depth: Android Package Manager and Package Installer](https://dzone.com/articles/depth-android-package-manager)\n4. [APK安装过程及原理详解](http://blog.csdn.net/hdhd588/article/details/6739281)\n5. [Android应用程序安装过程源代码分析](http://blog.csdn.net/luoshengyang/article/details/6766010)\n6. [Android内核开发：浅析APK的安装过程](http://ticktick.blog.51cto.com/823160/1669525)\n7. [android APK应用安装过程以及默认安装路径](https://www.cnblogs.com/sunshine-anycall/p/3544345.html)\n8. [Android应用安装过程及原理](https://my.oschina.net/wizardmerlin/blog/520283)\n9. [ADB原理与adb常用命令](http://blog.csdn.net/eleven521/article/details/22747345)\n\n<https://creativecommons.org/licenses/by-sa/4.0/> 版权声明：本文为博主原创文章，遵循 [CC 4.0 BY-SA](https://creativecommons.org/licenses/by-sa/4.0/) 版权协议，转载请附上原文出处链接和本声明。\n\n本文链接：<https://blog.csdn.net/zhangxu0922/article/details/51941070>\n\n\n[原作者删帖](https://www.its404.com/copyright) [不实内容删帖](https://www.its404.com/copyright) [广告或垃圾文章投诉](https://www.its404.com/copyright)\n"
}
