【Android FrameWork】延伸阅读: Android应用安装过程

Android应用安装过程

Android应用安装是系统核心流程之一,涉及Framework层的逻辑调度、Binder跨进程通信、C++层的底层文件操作与系统调用,贯穿了应用包解析、权限校验、Dex优化、目录创建等关键环节。

本文将从用户触发安装系统完成部署的全链路,结合Framework(Java)和Native(C++)层源码,拆解Android 11(API 30)的应用安装核心流程。

整体流程

Android应用安装可分为触发阶段、Framework层处理阶段、Native层执行阶段、收尾阶段四大环节,核心参与者包括:

  • Framework层:PackageManagerService(PMS)、PackageInstaller、PackageParser、Installer(Java层代理);
  • Native层:installd守护进程(C++)、dex2oat工具(Dex优化)、bionic库(系统调用);
  • 其他组件:Binder驱动(跨进程通信)、SELinux(权限管控)、PackageManager(应用层接口)。

整体流程链路:

复制代码
应用层触发安装(如PM命令/应用市场)→ PackageInstaller(Framework)→ PMS核心处理 → Installer(Java)→ Binder调用installd(C++)→ 底层文件操作 → PMS更新包信息 → 完成安装

阶段1:安装触发与Framework层入口

应用安装的触发方式包括:pm install命令、应用市场下载安装、ADB安装、系统预置应用安装等,所有触发方式最终都会走到PMS的installPackage系列接口。

1 入口:PackageInstaller的安装请求

以应用市场安装为例,应用层通过PackageInstaller.Session提交安装请求,核心源码如下(Framework层):

java 复制代码
// PackageInstaller.java(frameworks/base/core/java/android/content/pm/PackageInstaller.java)
public Session openSession(long sessionId) throws IOException {
    // 获取PMS的Binder代理,发起跨进程请求
    IPackageInstaller session = mService.openSession(sessionId);
    return new Session(this, session, sessionId);
}

// Session.java(内部类)
public void commit(IntentSender statusReceiver) throws IOException {
    try {
        // 提交安装请求,最终调用PMS的installStage方法
        mSession.commit(statusReceiver);
    } catch (RemoteException e) {
        throw e.rethrowAsRuntimeException();
    }
}

核心逻辑 :应用层通过PackageInstaller封装安装参数(APK路径、安装标志、用户ID),通过Binder跨进程调用PMS的安装接口,完成安装请求的传递。

2 PMS接收请求:installStage方法

PMS是安装流程的"总调度中心",installStage方法接收安装请求后,先做前置校验,再启动安装流程:

java 复制代码
// PackageManagerService.java
void installStage(PackageInstallArgs args, PackageInstalledInfo res) {
    // 1. 权限校验:检查调用方是否有INSTALL_PACKAGES权限(系统应用/签名校验)
    if (!checkInstallPermission(args.installerUid, args.packageName)) {
        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_DENIED);
        finishInstall(args, res);
        return;
    }

    // 2. 解析APK包:调用PackageParser解析AndroidManifest.xml
    PackageParser.Package pkg = parsePackage(args.apkPath, parseFlags);
    
    // 3. 校验APK合法性:签名、版本、包名冲突、SELinux规则
    if (!verifyPackageSignature(pkg, args)) {
        res.setError(PackageManager.INSTALL_FAILED_INVALID_SIGNATURE);
        finishInstall(args, res);
        return;
    }

    // 4. 启动异步安装流程(避免阻塞PMS主线程)
    mHandler.post(() -> processInstallRequest(args, pkg, res));
}

关键动作

  • 权限校验:仅系统应用(如应用市场、Settings)或拥有INSTALL_PACKAGES权限的应用可触发安装;
  • 包解析:PackageParser解析APK中的AndroidManifest.xml,提取包名、版本、组件(Activity/Service)、权限声明等信息;
  • 签名校验:校验APK签名是否合法(系统应用需匹配系统签名,第三方应用需通过证书校验)。

阶段2:Framework层核心处理(Java)

PMS的processInstallRequest方法是Framework层安装逻辑的核心,负责协调目录创建、Dex优化、权限分配等环节,核心依赖Installer(Java层)与Native层的installd通信。

1 Installer(Java):与installd的通信代理

Installer是Framework层与Native层installd守护进程通信的桥梁,封装了Binder调用逻辑,核心源码如下:

java 复制代码
// Installer.java(frameworks/base/services/core/java/com/android/server/pm/Installer.java)
public class Installer {
    private final IBinder mInstalld; // 指向installd的Binder代理

    // 初始化:连接installd守护进程
    public Installer() {
        mInstalld = ServiceManager.getService("installd");
        if (mInstalld == null) {
            throw new RuntimeException("Failed to connect to installd");
        }
    }

    // 创建应用数据目录(调用installd的create_data_dir方法)
    public int createDataDir(String pkgName, int uid, int gid) {
        try {
            // Binder调用installd的create_data_dir接口
            return ((IInstalld) mInstalld).createDataDir(pkgName, uid, gid);
        } catch (RemoteException e) {
            return -1;
        }
    }

    // Dex优化(调用installd的dexopt方法)
    public int dexopt(String apkPath, String pkgName, int uid, String instructionSet) {
        try {
            return ((IInstalld) mInstalld).dexopt(apkPath, pkgName, uid, instructionSet);
        } catch (RemoteException e) {
            return -1;
        }
    }
}

核心作用 :将Framework层的安装指令(如创建目录、Dex优化)通过Binder传递给Native层的installd,由installd执行底层操作。

2 核心步骤:创建应用目录与Dex优化

PMS通过Installer调用Native层接口,完成应用安装的核心操作:

java 复制代码
// PackageManagerService.java - processInstallRequest方法
private void processInstallRequest(PackageInstallArgs args, PackageParser.Package pkg, PackageInstalledInfo res) {
    // 1. 分配UID/GID:每个应用对应唯一的UID(10000+),GID与UID一致
    int uid = assignNewUid(pkg.packageName);
    
    // 2. 创建应用目录:调用Installer的createDataDir方法
    int createResult = mInstaller.createDataDir(pkg.packageName, uid, uid);
    if (createResult != 0) {
        res.setError(PackageManager.INSTALL_FAILED_CREATE_DIR);
        finishInstall(args, res);
        return;
    }

    // 3. Dex优化:将APK中的dex文件优化为oat文件(提升运行效率)
    int dexoptResult = mInstaller.dexopt(
        args.apkPath, pkg.packageName, uid, Build.SUPPORTED_ABIS[0]
    );
    if (dexoptResult != 0) {
        res.setError(PackageManager.INSTALL_FAILED_DEXOPT);
        finishInstall(args, res);
        return;
    }

    // 4. 分配权限:为应用授予声明的权限(系统权限需校验,普通权限直接授予)
    grantPermissions(pkg, uid);

    // 5. 更新PMS内存数据库:将新安装的应用信息加入mPackages
    addPackageToInternalMap(pkg, uid);

    // 6. 持久化包信息:写入/packages.xml和/packages.list
    writePackageInfoToDisk(pkg);

    // 7. 完成安装:通知Launcher更新图标、发送安装完成广播
    finishInstall(args, res);
}

关键说明

  • UID分配:Android通过UID隔离应用进程,每个第三方应用分配唯一UID,系统应用使用固定UID(如1000);
  • Dex优化:dexopt调用dex2oat工具,将Dex文件编译为机器码(OAT文件),避免应用运行时实时编译,提升启动速度;
  • 持久化:packages.xml存储应用的包信息、权限、签名,packages.list存储包名与UID的映射,下次系统启动时PMS直接加载这些文件。

阶段3:Native层核心执行(C++)

Framework层的所有底层操作最终由installd守护进程(C++实现)执行,installd是Android系统启动时由init进程拉起的核心守护进程,负责应用安装/卸载的底层文件操作。

1 installd的启动与Binder服务注册

installd的入口在system/core/installd/installd.cpp,启动时注册Binder服务,核心源码:

cpp 复制代码
// installd.cpp
int main() {
    // 1. 初始化日志、SELinux
    android::base::InitLogging(nullptr, android::base::LogdLogger());
    selinux_initialize();

    // 2. 创建Binder服务端,注册到ServiceManager(服务名:installd)
    sp<IServiceManager> sm = defaultServiceManager();
    sp<InstalldNativeService> service = new InstalldNativeService();
    status_t ret = sm->addService(String16("installd"), service, false);
    if (ret != OK) {
        ALOGE("Failed to register installd service");
        return 1;
    }

    // 3. 启动Binder循环,等待Framework层调用
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

    return 0;
}

核心逻辑installd启动后注册为Binder服务,Framework层的Installer(Java)通过ServiceManager获取其代理,实现跨进程调用。

2 InstalldNativeService:底层操作的实现

InstalldNativeServiceinstalld的核心实现类,封装了创建目录、Dex优化、文件权限修改等操作,核心源码如下:

cpp 复制代码
// InstalldNativeService.cpp
status_t InstalldNativeService::createDataDir(const std::string& pkgname, int uid, int gid) {
    // 1. 构造应用数据目录路径:/data/data/<pkgname>
    std::string dataDir = StringPrintf("/data/data/%s", pkgname.c_str());

    // 2. 创建目录,设置权限(751),所有者为uid:gid
    if (mkdir(dataDir.c_str(), 0751) != 0 && errno != EEXIST) {
        ALOGE("mkdir failed for %s: %s", dataDir.c_str(), strerror(errno));
        return -1;
    }

    // 3. 设置目录的UID/GID(chown)
    if (chown(dataDir.c_str(), uid, gid) != 0) {
        ALOGE("chown failed for %s: %s", dataDir.c_str(), strerror(errno));
        return -1;
    }

    // 4. 设置SELinux上下文(确保目录符合SELinux规则)
    if (selinux_restorecon(dataDir.c_str()) != 0) {
        ALOGE("restorecon failed for %s: %s", dataDir.c_str(), strerror(errno));
        return -1;
    }

    return 0;
}

status_t InstalldNativeService::dexopt(const std::string& apk_path, const std::string& pkgname,
                                       int uid, const std::string& isa) {
    // 构造dex2oat命令:/system/bin/dex2oat --apk <apk_path> --output <oat_path>
    std::vector<std::string> args;
    args.push_back("/system/bin/dex2oat");
    args.push_back("--apk");
    args.push_back(apk_path);
    args.push_back("--output");
    args.push_back(StringPrintf("/data/dalvik-cache/%s@%s.oat", pkgname.c_str(), isa.c_str()));
    args.push_back("--instruction-set");
    args.push_back(isa);

    // 执行dex2oat命令(fork+exec)
    int result = execute(args, uid);
    return result == 0 ? OK : -1;
}

核心操作解析

  • createDataDir:创建应用私有数据目录/data/data/<包名>,设置权限为751(仅应用自身可读写,其他进程可执行),并通过chown设置目录所有者为应用UID;
  • dexopt:拼接dex2oat命令,通过fork+exec执行,将APK中的Dex文件编译为OAT文件(存储在/data/dalvik-cache);
  • SELinux管控:selinux_restorecon设置目录的SELinux上下文(如u:object_r:app_data_file:s0:c123,c456),确保应用只能访问自身目录。

3 底层系统调用

installd的所有操作最终依赖Linux系统调用,如:

  • mkdir:创建目录;
  • chown/chmod:修改文件/目录的所有者和权限;
  • fork/exec:执行dex2oat等外部工具;
  • unlink:删除文件(卸载时);
  • mount:挂载APK(针对应用分身/多用户场景)。

createDataDir中的mkdir为例,底层调用链:

cpp 复制代码
// bionic/libc/unistd/mkdir.cpp
int mkdir(const char* path, mode_t mode) {
    // 调用Linux系统调用sys_mkdir
    return syscall(__NR_mkdirat, AT_FDCWD, path, mode);
}

阶段4:安装收尾与系统通知

当Native层完成所有底层操作后,Framework层的PMS会完成收尾工作,确保应用可被系统识别和启动:

1 更新内存数据库与持久化

PMS将新安装的应用信息加入mPackages(内存中的包信息映射表),并写入/data/system/packages.xml/data/system/packages.list

xml 复制代码
<!-- packages.xml示例 -->
<package name="com.example.app" codePath="/data/app/com.example.app-1" uid="10123">
    <version code="1" name="1.0"/>
    <permissions>
        <permission name="android.permission.INTERNET" granted="true"/>
    </permissions>
    <signature>...</signature>
</package>

2 发送安装完成广播

PMS发送Intent.ACTION_PACKAGE_ADDED广播,通知系统组件(如Launcher、Settings)应用已安装:

java 复制代码
// PackageManagerService.java - finishInstall方法
private void finishInstall(PackageInstallArgs args, PackageInstalledInfo res) {
    // 发送广播
    Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED);
    intent.setData(Uri.parse("package:" + args.packageName));
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);

    // 通知Launcher更新应用图标
    notifyPackageChanged(args.packageName);
}

3 应用启动准备

Launcher接收到广播后,解析应用的AndroidManifest.xml中的图标和名称,添加到桌面;同时,PMS为应用的组件(Activity/Service)注册到AMS,确保应用可被启动。

关键异常场景与容错机制

Android在安装流程中设计了多层容错机制,避免因单点失败导致安装异常:

  1. 目录创建失败 :若createDataDir失败(如磁盘满、权限不足),PMS会回滚已创建的目录,返回INSTALL_FAILED_CREATE_DIR
  2. Dex优化失败 :若dexopt失败(如APK损坏、指令集不兼容),PMS会删除已创建的目录,返回INSTALL_FAILED_DEXOPT
  3. 签名校验失败 :若APK签名不合法,直接终止安装,返回INSTALL_FAILED_INVALID_SIGNATURE
  4. 包名冲突 :若已存在同名应用且未指定覆盖安装,返回INSTALL_FAILED_ALREADY_EXISTS

总结

Android应用安装流程体现了分层、解耦、安全的核心设计原则:

  1. 分层设计:Framework层负责逻辑调度(校验、权限、通知),Native层负责底层操作(文件、编译),通过Binder实现跨层通信;
  2. 解耦思想 :PMS不直接执行底层文件操作,而是通过Installer代理调用installd,降低模块耦合;
  3. 安全管控:多层校验(权限、签名、SELinux)确保只有合法应用能被安装,UID隔离确保应用数据安全;
  4. 性能优化:Dex预编译(dex2oat)避免运行时编译,提升应用启动速度;异步安装避免阻塞PMS主线程。
相关推荐
光头闪亮亮2 小时前
Android手持机扫码出入库的开发详解-6.APP下载更新
android
光头闪亮亮3 小时前
Android手持机扫码出入库的开发详解-7.SQLite CRUD操作
android
键来大师3 小时前
Android16 设置壁纸出现APK重启问题和悬浮控件等图标变成黑色图框
android·framework·rk3576
_李小白3 小时前
【Android FrameWork】第四十二天:PMS main函数
android
BoomHe3 小时前
Android LMK(Low Memory Killer)机制
android
时光呀时光慢慢走4 小时前
MAUI 开发安卓 MQTT 客户端:实现远程控制 (完整源码 + 避坑指南)
android·物联网·mqtt·c#
成都大菠萝4 小时前
2-2-44 快速掌握Kotlin-函数类型操作
android
有位神秘人5 小时前
Android中获取设备里面的音频文件
android
2501_915918415 小时前
使用 HBuilder 上架 iOS 应用时常见的问题与应对方式
android·ios·小程序·https·uni-app·iphone·webview