APK安装流程概述
Posted 浪里小白龙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了APK安装流程概述相关的知识,希望对你有一定的参考价值。
一. APK安装简介
APK为android
Package的缩写。
Android应用安装有如下四种方式:
1.系统应用安装――开机时完成,没有安装界面;
2.网络下载应用安装――通过market应用完成,没有安装界面;
3.ADB工具安装――没有安装界面;
4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。
应用安装涉及到如下几个目录:
- system/app----------------系统自带的应用程序,获得adb root权限才能删除;
- data/app-------------------用户程序安装的目录,安装时把apk 文件复制到此目录;
- data/data-------------------存放应用程序的数据;
- data/dalvik-cache---------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)。
二. 系统应用安装
1. 了解须知:
(1). 对于在/system/app和/data/app目录下的APK文件,在PackageManagerService的启动过程中,会扫描安装。
(2).PackageManagerService由system_server启动,它全面负责应用包的安装,卸载,权限检查等工作。
(3).在每次开机的时 候,PackageManagerService都会在其构造函数中,对指定的目录的APK进行扫描。对于没有安装的APK文件会触发安装过程。
2. 实现原理:
(1).
开机启动PackageManagerService,通过SystemServer.startBootstrapServices()
启动。
1 public static PackageManagerService main(Context context, Installer installer, 2 boolean factoryTest, boolean onlyCore) { 3 PackageManagerService m = HwServiceFactory.getHuaweiPackageManagerService(context, installer, 4 factoryTest, onlyCore); 5 ServiceManager.addService("package", m); 6 return m; 7 }
(2). PackageManagerService初始化,执行构造方法,分为六个重要步骤。
第一步:创建Settings对象,添加shareUserId;
1 mSettings = new Settings(mPackages); 2 mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, 3 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); 4 mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, 5 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); 6 mSettings.addSharedUserLPw("android.uid.log", LOG_UID, 7 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); 8 mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, 9 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); 10 mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, 11 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); 12 mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, 13 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
第二步:创建应用安装器Installer,来源是PackageManagerService参数之一。
第三步:构造SystemConfig,读取 ”/system/etc/permissions/*.xml” 资源,获取mSystemPermissions(系统权限),mGlobalGids(Group-ids),mAvailableFeatures(系统支持的features)属性。
执行顺序:
com.android.server.pm.PackageManagerService#PackageManagerService
--> com.android.server.SystemConfig#getInstance
--> com.android.server.SystemConfig#SystemConfig
--> com.android.server.SystemConfig#readPermissions
1 SystemConfig systemConfig = SystemConfig.getInstance(); 2 mGlobalGids = systemConfig.getGlobalGids(); 3 mSystemPermissions = systemConfig.getSystemPermissions(); 4 mAvailableFeatures = systemConfig.getAvailableFeatures();
第四步:创建系统消息处理线程。
1 mHandlerThread = new ServiceThread(TAG, 2 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); 3 mHandlerThread.start(); 4 mHandler = new PackageHandler(mHandlerThread.getLooper()); 5 Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
第五步:执行com.android.server.pm.Settings#readLPw, 读取安装包信息,并解析成对应的数据结构,包括以下重要文件:
-
packages.xml:记录系统中所有安装的应用信息,包括基本信息、签名和权限。
-
packages-backup.xml:packages.xml文件的备份。
-
packages.list:保存普通应用的数据目录和uid等信息。
-
packages-stopped.xml:记录系统中被强制停止运行的应用信息。系统在强制停止某个应用时,会讲应用的信息记录到该文件中。
-
packages-stopped-backup.xml:pacakges-stopped.xml文件的备份。
这几个目录在创建Settings对象的时候,就已经被封装成对应的File文件。
packages-backup.xml是packages.xml的备份文件。在每次写packages.xml文件的时候,都会将旧的 packages.xml文件先备份,这样做是为了防止写文件过程中文件以外损坏,还能从旧的文件中恢复。
package- restrictions.xml保存着受限制的APP的状态,比如某个APP处于disable状态,或者某个APP具有更高的优先级等。
第六步:执行PackageManagerService#scanDirLI。
监控和扫描系统包安装目录:
- /system/framework 系统库
- /system/app 默认的系统应用
- /vendor/app 厂商定制的应用
扫描非系统apk信息:
- /data/app/
- /system/preloadapp/
- /data/app-private/
跟踪扫描安装过程:
①:构建PackageParser对象
调用PackageManagerService#scanPackageLI(xxx) 方法。
②:构建一个PackageParser.Package对象并返回
调用PackageParser#parsePackage(java.io.File, int) 方法,扫描APK安装包的AndroidManifest.xml文件和提取证书信息,以此信息构建一个PackageParser.Package对象,并将其返回;
③:将PackageParser.Package对象的信息保存到PackageManagerService中
其中包括ContentProvider,Activity,Service,BroadcastReceiver;
④:构建PackageSetting
对象
执行以下代码:
.PackageManagerService#scanPackageLI(xxx)
--> .PackageManagerService#scanPackageDirtyLI
构建PackageSetting 对象,这个对象中保存的信息最后会通过writeLPr写入到/data/system/packages.xml文件中去。
以上几个步骤可以用两个图代替:
----------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
⑤:调用mInstaller.createUserData()函数创建数据目录
调用PackageManagerService#createDataDirsLI方法,给installd发送消息,为应用程序创建对应的数据目录,如果已经存在,也会重新创建一遍。
⑥:调用mInstaller.install()函数完成APK安装
1 private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) { 2 int[] users = sUserManager.getUserIds(); 3 int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo); 4 if (res < 0) { 5 return res; 6 } 7 for (int user : users) { 8 if (user != 0) { 9 res = mInstaller.createUserData(volumeUuid, packageName, 10 UserHandle.getUid(user, uid), user, seinfo); 11 if (res < 0) { 12 return res; 13 } 14 } 15 } 16 return res; 17 }
Installer.install()函数和createUserData()进行完成了命令组装工作,在组装完命令之后,将命令传递给InstallerConnectio.java处理。
1 public int install(String uuid, String name, int uid, int gid, String seinfo) { 2 StringBuilder builder = new StringBuilder("install"); 3 builder.append(\' \'); 4 builder.append(escapeNull(uuid)); 5 builder.append(\' \'); 6 builder.append(name); 7 builder.append(\' \'); 8 builder.append(uid); 9 builder.append(\' \'); 10 builder.append(gid); 11 builder.append(\' \'); 12 builder.append(seinfo != null ? seinfo : "!"); 13 return mInstaller.execute(builder.toString()); 14 }
通过分析InstallerConnection.java得到以下结论:
1. InstallerConnection连接一个名为Installd的服务。
2. Install具体的命令有Installd完成。
以下是InstallerConnection连接Installd服务的代码
1 private boolean connect() { 2 if (mSocket != null) { 3 return true; 4 } 5 Slog.i(TAG, "connecting..."); 6 try { 7 mSocket = new LocalSocket(); 8 9 LocalSocketAddress address = new LocalSocketAddress("installd", 10 LocalSocketAddress.Namespace.RESERVED); 11 12 mSocket.connect(address); 13 14 mIn = mSocket.getInputStream(); 15 mOut = mSocket.getOutputStream(); 16 } catch (IOException ex) { 17 disconnect(); 18 return false; 19 } 20 return true; 21 }
Installed介绍
Installd是一个native进程,该进程启动一个socket,然后处理来自Installer的命令。
PackageManagerService通过套接字的方式访问installd服务进程,在Android启动脚本init.rc中通过服务配置启动了installd服务进程。
1 service installd /system/bin/installd 2 class main 3 socket installd stream 600 system system
通过以上配置,init进程就会启动installd服务进程了。
Installed
进程的入口是main函数,该函数首先初始化一些变量就安装目录,然后从环境变量中取得installd套件字的句柄值,然后进入监听此socket,当客户端发送过来请求时,接收客户端的请求,并读取客户端发送过来的命令数据,并根据读取的客户端命令来执行命令操作。
1 int main(const int argc __unused, char *argv[]) { 2 char buf[BUFFER_MAX]; 3 struct sockaddr addr; 4 socklen_t alen; 5 int lsocket, s; 6 int selinux_enabled = (is_selinux_enabled() > 0); 7 8 setenv("ANDROID_LOG_TAGS", "*:v", 1); 9 android::base::InitLogging(argv); 10 11 ALOGI("installd firing up\\n"); 12 13 union selinux_callback cb; 14 cb.func_log = log_callback; 15 selinux_set_callback(SELINUX_CB_LOG, cb); 16 17 if (initialize_globals() < 0) { 18 ALOGE("Could not initialize globals; exiting.\\n"); 19 exit(1); 20 } 21 22 if (initialize_directories() < 0) { 23 ALOGE("Could not create directories; exiting.\\n"); 24 exit(1); 25 } 26 27 if (selinux_enabled && selinux_status_open(true) < 0) { 28 ALOGE("Could not open selinux status; exiting.\\n"); 29 exit(1); 30 } 31 32 lsocket = android_get_control_socket(SOCKET_PATH); 33 if (lsocket < 0) { 34 ALOGE("Failed to get socket from environment: %s\\n", strerror(errno)); 35 exit(1); 36 } 37 if (listen(lsocket, 5)) { 38 ALOGE("Listen on socket failed: %s\\n", strerror(errno)); 39 exit(1); 40 } 41 fcntl(lsocket, F_SETFD, FD_CLOEXEC); 42 43 for (;;) { 44 alen = sizeof(addr); 45 s = accept(lsocket, &addr, &alen); 46 if (s < 0) { 47 ALOGE("Accept failed: %s\\n", strerror(errno)); 48 continue; 49 } 50 fcntl(s, F_SETFD, FD_CLOEXEC); 51 52 ALOGI("new connection\\n"); 53 for (;;) { 54 unsigned short count; 55 if (readx(s, &count, sizeof(count))) { 56 ALOGE("failed to read size\\n"); 57 break; 58 } 59 if ((count < 1) || (count >= BUFFER_MAX)) { 60 ALOGE("invalid size %d\\n", count); 61 break; 62 } 63 if (readx(s, buf, count)) { 64 ALOGE("failed to read command\\n"); 65 break; 66 } 67 buf[count] = 0; 68 if (selinux_enabled && selinux_status_updated() > 0) { 69 selinux_android_seapp_context_reload(); 70 } 71 if (execute(s, buf)) break; 72 } 73 ALOGI("closing connection\\n"); 74 close(s); 75 } 76 77 return 0; 78 }
main函数调用execute函数,执行客户发送过来的请求命令。
1 以上是关于APK安装流程概述的主要内容,如果未能解决你的问题,请参考以下文章