从源码角度解析Android中APK安装过程

本文从源码角度详细解析Android中APK的安装过程,涵盖系统应用、网络下载应用、命令行和外部设备安装的四种方式。重点介绍了APK安装的四大步骤:拷贝apk、解压、解析AndroidManifest.xml和显示icon。涉及关键目录如system/app、data/app、data/data和data/dalvik-cache。
摘要由CSDN通过智能技术生成

从源码角度解析Android中APK的安装过程

1. Android中APK简介

Android应用Apk的安装有如下四种方式:

1.1 系统应用安装

没有安装界面,在开机时自动完成

1.2 网络下载应用安装

没有安装界面,在应用市场完成

1.3 ADB命令安装

没有安装界面,通过命令直接安装

1.4 外部设备安装

有安装界面,通过SD卡等外部设备安装,由packageInstaller处理安装逻辑
2. APK安装涉及到的几个常用目录
  • system/app : 系统自带的应用程序,获得root权限才能删除

  • data/app : 用户程序安装目录,安装时会把apk文件复制到此目录下

  • data/data : 存放应用程序的数据

  • data/dalvik-cache : 将apk中的dex文件安装到该目录下(dex文件是dalvik虚拟机的可执行文件,大小约为原始apk的四分之一)

3. APK安装的四大步骤

(1)拷贝apk到指定的目录

默认情况下,用户安装的apk首先会拷贝到/data/app下,用户有访问/data/app目录的权限,但系统出厂的apk文件
会被放到/system分区下,包括/system/app,/system/vendor/app,以及/system/priv-app等。该分区需要
root权限的用户才能访问。

(2)加压apk、拷贝文件、创建应用的数据目录

为了加快APP的启动速度,apk在安装的时候,会首先将APP的可执行文件(dex)拷贝到/data/dalvik-cache目录
下,缓存起来。再在/data/data/目录下创建应用程序的数据目录(以应用包名命令),用来存放应用的数据库、xml
文件、cache、二进制的so动态库等。

(3)解析apk的AndroidManifest.xml文件

在安装apk的过程中,会解析apk的AndroidManifest.xml文件,将apk的权限、应用包名、apk的安装位置、版本、
userID等重要信息保存在/data/system/packages.xml文件中。这些操作都是在PackageManagerService中完成
的。

(4)显示icon图标

应用程序经过PMS中的逻辑处理后,相当于已经注册好了,如果想要在Android桌面上看到icon图标,则需要
Launcher将系统中已经安装的程序展现在桌面上。
4. APK安装的预备知识点

(1)PackageManagerService是由SystemServer启动,PMS负责应用的安装、卸载、权限检查等工作

(2)在/system/app和/data/app目录下的apk文件,PMS在启动过程中,都会扫描安装

(3)每次开机时,PMS都会在构造函数中对指定目录下的apk进行扫描,没有安装的apk就会触发安装。

(4) 本文的源码是基于Android6.0

5. 系统应用安装

在创建PackageManagerService实例时,会在PMS的构造函数中开始执行安装应用程序的逻辑。在PMS的构造函数中做了如下几点重要操作。

(1)创建Settings对象,添加shareUserId

    mSettings = new Settings(mPackages);
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

(2)通过PackageManagerService构造函数参数获取应用安装器Installer

mInstaller = installer;

(3)获取SystemConfig实例,读取“/system/etc/permissions/*.xml”资源文件

从资源文件中获取mGlobalsGids(Group-ids)、mSystemPermissions(系统权限)、mAvailableFeatures(系统支持的features)属性。

	SystemConfig systemConfig = SystemConfig.getInstance();
    mGlobalGids = systemConfig.getGlobalGids();
    mSystemPermissions = systemConfig.getSystemPermissions();
    mAvailableFeatures = systemConfig.getAvailableFeatures();

(4)创建系统消息处理线程

	mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
    mHandlerThread.start();
    mHandler = new PackageHandler(mHandlerThread.getLooper());
    Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

(5)执行com.android.server.pm.Settings中的readLPw方法,读取安装包中的信息,并解析成对应的数据结构。

	File dataDir = Environment.getDataDirectory();
    mAppDataDir = new File(dataDir, "data");
    mAppInstallDir = new File(dataDir, "app");
    mAppLib32InstallDir = new File(dataDir, "app-lib");
    mAsecInternalPath = new File(dataDir, "app-asec").getPath();
    mUserAppDataDir = new File(dataDir, "user");
    mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

    sUserManager = new UserManagerService(context, this,
            mInstallLock, mPackages);

    // Propagate permission configuration in to package manager.
    ArrayMap<String, SystemConfig.PermissionEntry> permConfig
            = systemConfig.getPermissions();
    for (int i=0; i<permConfig.size(); i++) {
        SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
        BasePermission bp = mSettings.mPermissions.get(perm.name);
        if (bp == null) {
            bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
            mSettings.mPermissions.put(perm.name, bp);
        }
        if (perm.gids != null) {
            bp.setGids(perm.gids, perm.perUser);
        }
    }

    ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
    for (int i=0; i<libConfig.size(); i++) {
        mSharedLibraries.put(libConfig.keyAt(i),
                new SharedLibraryEntry(libConfig.valueAt(i), null));
    }

    mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

    mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
            mSdkVersion, mOnlyCore);

其中,读取的重要文件有如下几个:

  • packages.xml:记录了系统中所有安装应用的信息,包括基本信息、签名和权限。

  • packages-backup.xml:packages.xml的备份文件

  • packages.list:保存普通应用的数据目录和uid等信息

  • packages-stopped.xml:记录系统中被强制停止运行应用的信息。系统在强制停止某个应用时,会将应用的信息记录到该文件中

  • packages-stopped-backup.xml:packages-stopped.xml的备份文件

这几个目录在创建Settings对象时就已经被封装成了对应的File文件。

(6)执行PMS中的scanDirLI方法扫描系统安装目录和非系统apk信息

	File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
    scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

    // Find base frameworks (resource packages without code).
    scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR
            | PackageParser.PARSE_IS_PRIVILEGED,
            scanFlags | SCAN_NO_DEX, 0);

    // Collected privileged system packages.
    final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
    scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR
            | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

    // Collect ordinary system packages.
    final File systemAppDir = new File(Environment.getRootDirectory(), "app");
    scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

    // Collect all vendor packages.
    File vendorAppDir = new File("/vendor/app");
    try {
        vendorAppDir = vendorAppDir.getCanonicalFile();
    } catch (IOException e) {
        // failed to look up canonical path, continue with original one
    }
    scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

    // Collect all OEM packages.
    final File oemAppDir = new File(Environment.getOemDirectory(), "app");
    scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

其中,系统安装目录有:

  • /system/framework 系统库

  • /system/app 默认的系统应用

  • /vendor/app 厂商定制的应用

非系统apk信息目录:

  • /data/app/

  • /system/priv-app/

  • /data/app-private/

到此为止,PMS构造函数中主要的逻辑操作就介绍完了。

继续探究扫描安装过程:

(1)深入到PackageManagerService—>scanDirLI方法中

private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
    final File[] files = dir.listFiles();
    if (Arr
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值