安卓应用安装过程学习

声明:此文章来自http://shuwoom.com/?p=60的学习记录

启动式安装

public static final IPackageManager main(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);ServiceManager.addService("package", m);return m;
}

main函数中创建PackageManagerService服务对象,并把服务添加到ServiceManager中

ServiceManager是Android系统Binder进程通信机制的守护进程,一直运行在后台。它主要负责管理系统中的Binder对象。

应用程序在安装时涉及到如下几个重要目录:

system/app

系统应用程序的目录

data/app

用户程序安装的目录

data/data

存放应用程序数据的目录

data/dalvik-cache

存放的是经过优化的dex文件

PackageManagerService是Android系统的核心服务之一,在系统启动的时候由SystemServer组件负责启动起来。PackageManagerService用于管理系统中的所有安装包信息以及应用程序的安装和卸载,但是实际应用程序的安装卸载并不是由PackageManagerService亲自完成,而是通过socket通信,PackageManagerService来访问installd服务来实现应用程序的安装和卸载。

public class SystemServer {.../*** Called to initialize native system services.*/private static native void nativeInit();public static void main(String[] args) {...System.loadLibrary("android_servers");Slog.i(TAG, "Entered the Android system server!");// Initialize native services.nativeInit();// This used to be its own separate thread, but now it is// just the loop we run on the main thread.ServerThread thr = new ServerThread();thr.initAndLoop();}
}

SystemServer中的ServerThread来启动PackageManagerService

class ServerThread {private static final String TAG = "SystemServer";……ContentResolver mContentResolver;……public void initAndLoop() {EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,SystemClock.uptimeMillis());Looper.prepareMainLooper();……boolean onlyCore = false;boolean firstBoot = false;……try {Slog.i(TAG, "Display Manager");display = new DisplayManagerService(context, wmHandler);ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);Slog.i(TAG, "Telephony Registry");telephonyRegistry = new TelephonyRegistry(context);ServiceManager.addService("telephony.registry", telephonyRegistry);Slog.i(TAG, "Scheduling Policy");ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());AttributeCache.init(context);if (!display.waitForDefaultDisplay()) {reportWtf("Timeout waiting for default display to be initialized.",new Throwable());}Slog.i(TAG, "Package Manager");// 处于加密状态时,紧解析核心应用String cryptState = SystemProperties.get("vold.decrypt");if (ENCRYPTING_STATE.equals(cryptState)) {Slog.w(TAG, "Detected encryption in progress - only parsing core apps");onlyCore = true;} else if (ENCRYPTED_STATE.equals(cryptState)) {Slog.w(TAG, "Device encrypted - only parsing core apps");onlyCore = true;}pm = PackageManagerService.main(context, installer,factoryTest != SystemServer.FACTORY_TEST_OFF,onlyCore);……}
}

PackageManagerService构造函数如下

public PackageManagerService(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {synchronized (mInstallLock) {// writersynchronized (mPackages) {mHandlerThread.start();mHandler = new PackageHandler(mHandlerThread.getLooper());Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(),WATCHDOG_TIMEOUT);File dataDir = Environment.getDataDirectory();mAppDataDir = new File(dataDir, "data");  mAppInstallDir = new File(dataDir, "app");  mAppLibInstallDir = new File(dataDir, "app-lib"); mAsecInternalPath = new File(dataDir, "app-asec").getPath();  mUserAppDataDir = new File(dataDir, "user");  mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); ……mFrameworkDir = new File(Environment.getRootDirectory(), "framework");mDalvikCacheDir = new File(dataDir, "dalvik-cache");……// Find base frameworks (resource packages without code).mFrameworkInstallObserver = new AppDirObserver(frameworkDir.getPath(), OBSERVER_EVENTS, true, false);mFrameworkInstallObserver.startWatching();//扫描”/system/framework”目录下的apkscanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED,scanMode | SCAN_NO_DEX, 0);// Collected privileged system packages.File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");mPrivilegedInstallObserver = new AppDirObserver(privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);mPrivilegedInstallObserver.startWatching();//扫描”/system/priv-app”目录下的apkscanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);// Collect ordinary system packages.File systemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver(systemAppDir.getPath(), OBSERVER_EVENTS, true, false);mSystemInstallObserver.startWatching();//扫描”/system/app”目录下的apkscanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);// Collect all vendor packages.File vendorAppDir = new File("/vendor/app");mVendorInstallObserver = new AppDirObserver(vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);mVendorInstallObserver.startWatching();// vender目录其实连接到/system/vendor,实际扫描:/system/vendor/app目录下的apkscanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");mInstaller.moveFiles();// Prune any system packages that no longer exist.final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();//由上一部分内容知道,默认情况下磁盘加密状态关闭,即mOnlyCore状态falseif (!mOnlyCore) {EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());mAppInstallObserver = new AppDirObserver(mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);mAppInstallObserver.startWatching();//扫描”/data/app”目录下的apkscanDirLI(mAppInstallDir, 0, scanMode, 0);mDrmAppInstallObserver = new AppDirObserver(mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false);mDrmAppInstallObserver.startWatching();//扫描”/data/app-private”目录下的apkscanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,scanMode, 0);……} ……..
}

这里调用了很多scanDirLI,这个函数调用了scanPackageLI

private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {String[] files = dir.list();……int i;for (i=0; i<files.length; i++) {File file = new File(dir, files[i]);//只扫描apk后缀的文件if (!isPackageFilename(files[i])) {// Ignore entries which are not apk'scontinue;}PackageParser.Package pkg = scanPackageLI(file,flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);……}
}

scanPackageLI功能如下

private PackageParser.Package scanPackageLI(File scanFile,int parseFlags, int scanMode, long currentTime, UserHandle user) {……String scanPath = scanFile.getPath();parseFlags |= mDefParseFlags;PackageParser pp = new PackageParser(scanPath);pp.setSeparateProcesses(mSeparateProcesses);pp.setOnlyCoreApps(mOnlyCore);//解析安装包final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);……//保存解析后的安装包PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode| SCAN_UPDATE_SIGNATURE, currentTime, user);……return scannedPkg;
}

其调用了parsePackage用于获取apk中的资源对象res和对Androidmanifest.xml文件进行格式化,并调用另一个parsePackage函数进一步做解析,也是package类真正生成的地方

啥是package?

package类是安卓框架中用于表示一个应用程序包的结构和信息的类。它包含了应用程序的多个方面的信息,包括:

  • 包名:唯一标识应用程序的字符串,通常是反向域名格式(例如,com.example.myapp)。
  • 版本信息:包括应用程序的版本号和版本代码,帮助识别应用的更新和兼容性。

  • 权限:声明应用所需的权限,例如访问互联网、读取联系人等。

  • 组件:描述应用程序包含的组件,如活动(Activity)、服务(Service)、内容提供者(Content Provider)和广播接收器(Broadcast Receiver)。

保存了app的信息之后 调用createDataDirsLI进行真正的安装操作

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);if (res < 0) {return res;}}}return res;
}

调用了install类的install方法 install调用execute execute调用transaction transaction进行客户端-服务端通信,首先判断客户端-服务端是否连接

然后调用writeCommand向服务端通过socket,向服务端发送指令

如果发送的指令是install 服务端就会调用do_install进行安装 do_install调用了commands.c文件的install函数执行安装

int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
{char pkgdir[PKG_PATH_MAX];  //程序目录路径最长256char libsymlink[PKG_PATH_MAX];char applibdir[PKG_PATH_MAX];struct stat libStat;// 权限判断if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {ALOGE("invalid uid/gid: %d %d\n", uid, gid);return -1;}// 组合应用程序安装目录pkgdir=”/data/data/应用程序包名”if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {ALOGE("cannot create package path\n");return -1;}……// 创建应用程序安装目录pkgdir=”/data/data/应用程序包名”if (mkdir(pkgdir, 0751) < 0) {ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));return -1;}// 修改应用程序安装目录pkgdir=”/data/data/应用程序包名”权限if (chmod(pkgdir, 0751) < 0) {ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));unlink(pkgdir);return -1;}……return 0;
}

点击安装

ADB安装

商店安装

总结:实际上四种安装方式都有用到PackageManagerService,而PackageManagerService也都是通过客户端-服务端的方式,向服务端发送命令进行安装的,也是四种安装方式的共同点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/887175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

输入/输出管理 III(磁盘和固态硬盘)

一、磁盘 【总结】&#xff1a; 磁盘&#xff08;Disk&#xff09;是由表面涂有磁性物质的物理盘片&#xff0c;通过一个称为磁头的导体线圈从磁盘存取数据。在读&#xff0f;写操作期间&#xff0c;磁头固定&#xff0c;磁盘在下面高速旋转。如下图所示&#xff1a; 磁盘盘面…

使用flink编写WordCount

1. env-准备环境 2. source-加载数据 3. transformation-数据处理转换 4. sink-数据输出 5. execute-执行 流程图&#xff1a; DataStream API开发 //nightlies.apache.org/flink/flink-docs-release-1.13/docs/dev/datastream/overview/ 添加依赖 <properties>&l…

# issue 4 进程控制函数

目录 一、进程控制函数一 二、进程控制函数二 启动进程&#xff1a;&#xff08;exec系列&#xff09; 创建新进程&#xff1a; 测试代码&#xff1a; 测试结果&#xff1a; 三、进程控制函数三 结束进程&#xff1a; 测试代码&#xff1a; 测试结果&#xff1a; 四、…

Java项目实战II基于SpringBoot的共享单车管理系统开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在共享经济蓬勃发展的今天…

Linux 网络编程之UDP套接字

前言 前面我们对网络的发展&#xff0c;网络的协议、网路传输的流程做了介绍&#xff0c;最后&#xff0c;我们还介绍了 IP 和 端口号&#xff0c;ip port 叫做 套接字 socket&#xff0c; 本期我们就来介绍UDP套接字编程&#xff01; 目录 1、预备知识 1.1 传输层协议: T…

---Arrays类

一 java 1.Arrays类 1.1 toString&#xff08;&#xff09; 1.2 arrays.sort( )-----sort排序 1&#xff09;直接调用sort&#xff08;&#xff09; Arrays.sort() 方法的默认排序顺序是 从小到大&#xff08;升序&#xff09;。 2&#xff09;定制排序【具体使用时 调整正负…

Java 对象头、Mark Word、monitor与synchronized关联关系以及synchronized锁优化

1. 对象在内存中的布局分为三块区域&#xff1a; &#xff08;1&#xff09;对象头&#xff08;Mark Word、元数据指针和数组长度&#xff09; 对象头&#xff1a;在32位虚拟机中&#xff0c;1个机器码等于4字节&#xff0c;也就是32bit&#xff0c;在64位虚拟机中&#xff0…

6.7机器学习期末复习题

空间 样本空间 就是属性的所有可能情况&#xff0c;包括了一切可能出现或不可能出现的所有样本情况 版本空间&假设空间 假设空间就是在样本空间的基础上&#xff0c;给所有属性都加了一个通配符&#xff0c;表示任意即可&#xff1b;以及加上了一个空集&#xff0c;表示…

Qt界面设计时使各控件依据窗口缩放进行栅格布局的方法

图1 最终效果 想要达成上述图片的布局效果&#xff0c;具体操作如下&#xff1a; 新建一窗体&#xff1a; 所需控件如下&#xff1a; Table View控件一个&#xff1b; Group Box控件一个&#xff1b; Push Button控件2个&#xff1b; Horiziontal Spacer控件2个&#xf…

mac安装Pytest、Allure、brew

安装环境 安装pytest 命令 pip3 install pytest 安装allure 命令&#xff1a;brew install allure 好吧 那我们在安装allure之前 我们先安装brew 安装brew 去了官网复制了命令 还是无法下载 如果你们也和我一样可以用这个方法哦 使用国内的代码仓库来执行brew的安装脚本…

数据结构C语言描述5(图文结合)--队列,数组、链式、优先队列的实现

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法&#xff1b;有C基础即可跟着学习&#xff0c;代码均可运行&#xff1b;准备考研的也可跟着写&#xff0c;个人感觉&#xff0c;如果时间充裕&#xff0c;手写一遍比看书、刷题管用很多&#xff0c;这也是本人采用纯C语言…

一篇文章了解机器学习

一篇文章了解机器学习&#xff08;上&#xff09; 一、软件版本安装二、数据集的加载三、数据集的切分四、数据特征提取及标准化1、字典数据的特征提取2、文本特征向量的提取3、数据标准化处理 四、特征降维注&#xff1a;训练器的区别&#xff1a;&#xff1a;五、模型的训练与…

day03(单片机高级)RTOS

目录 RTOS(实时操作系统) 裸机开发模式 轮询方式 前后台&#xff08;中断方式&#xff09; 改进&#xff08;前后台&#xff08;中断&#xff09;&#xff09;定时器 裸机进一步优化 裸机的其他问题 RTOS的概念 什么是RTOS 为什么要使用 RTOS RTOS的应用场景 RTOS的…

Hello-Go

Hello-Go 环境变量 GOPATH 和 GOROOT &#xff1a;不同于其他语言&#xff0c;go中没有项目的说法&#xff0c;只有包&#xff0c;其中有两个重要的路径&#xff0c;GOROOT 和 GOPATH Go开发相关的环境变量如下&#xff1a; GOROOT&#xff1a;GOROOT就是Go的安装目录&…

pytorch官方FasterRCNN代码详解

本博文转自捋一捋pytorch官方FasterRCNN代码 - 知乎 (zhihu.com)&#xff0c;增加了其中代码的更详细的解读&#xff0c;以帮助自己理解该代码。 代码理解的参考Faster-RCNN全面解读(手把手带你分析代码实现)---前向传播部分_手把手faster rcnn-CSDN博客 1. 代码结构 作为 to…

全志T113双核异构处理器的使用基于Tina Linux5.0——RTOS系统定制开发

8、RTOS系统定制开发 此处以在rtos/components/aw目录下创建一个简单的软件包为例&#xff0c;帮助客户了解RTOS环境&#xff0c;为RTOS系统定制开发提供基础。 RTOS环境下的软件包主要由三部分组成&#xff0c;源文件&#xff0c;Makefile&#xff0c;Kconfig&#xff0c;如下…

springboot实战(13)(@PatchMapping、@RequestParam、@URL、ThreadLocal线程局部变量)

目录 一、PATCH请求方式。 二、实现用户更新头像功能。 三、注解RequestParam。 四、注解URL。&#xff08;对传来的参数是否是合法地址进行校验&#xff09; 一、PATCH请求方式。 patch中文翻译&#xff1a;局部、小块。PATCH 请求主要用于对已存在的资源进行局部修改&#xf…

nvm安装node遇到的若干问题(vscode找不到npm文件、环境变量配置混乱、npm安装包到D盘)

问题一&#xff1a;安装完nvm后需要做哪些环境变量的配置&#xff1f; 1.打开nvm文件夹下的setting文件&#xff0c;设置nvm路径和安装node路径&#xff0c;并添加镜像。 root: D:\software\nvm-node\nvm path: D:\software\nvm-node\nodejs node_mirror: https://npmmirror.c…

面向FWA市场!移远通信高性能5G-A模组RG650V-NA通过北美两大重要运营商认证

近日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;其旗下符合3GPP R17标准的新一代5G-A模组RG650V-NA成功通过了北美两家重要运营商认证。凭借高速度、大容量、低延迟、高可靠等优势&#xff0c;该模组可满足CPE、家庭/企业网关、移动热点、高清视频…

2024年11月21日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael项目介绍&#xff1a;正在构建一个由社区支持的现代化Salesforce替代品。项目star数&#xff1a;21,798项目fork数&#xff1a;2,347 项目名称&#xff1a;p…