从源码角度看Android应用安装

简介

我之前的文章里,一般都是集中分析AMS, IMS, WMS以及View控件方面的原理,然而这些组件的分析其实有一个前提:PMS中需要预先加载应用相关的组件、库以及资源文件。可以这么说,倘若没有PMS的服务的话,所有应用是无法被加载到系统中运行的。

PMS提供的所有功能中,最核心的当属应用安装服务。作为一个普通的用户,最常见的场景是通过应用商店,或者自己手动从网络下载apk,在文件管理器中手动安装应用。作为一个开发者,最常用的是AS的Run按钮,本质上最终会使用脚本调用adb install服务来实现应用的安装。

这篇文章里,我将会从源码的角度,着重梳理、分析各个场景下的安装功能实现流程。最终我们能发现,所有的安装场景其实是殊途同归,最终调用到了PMS的scanPackageDirtyLI来实现安装功能,而所谓的安装,其实是对apk文件的解析、加载。

Android 应用安装场景总结

安卓安装源码大部分逻辑都在PMS中,相对比与IMS与View控件花哨的设计,PMS安装实现比较"原始",常常会调用到巨无霸"方法"。因为调用流程并不复杂,这里就不画类图、时序图了,直接上一张安装场景总结图:

安装场景 入口函数 触发时机
系统应用安装 SystemServer.main() 系统启动时
通过安装器安装 PackageInstallerActivity.startInstall() 在安装器界面点击安装
通过adb install安装 PM.runInstall() 输入adb install xxx.apk进行安装
应用商店自动安装 通过Accessibility自动点击安装按钮 AcessibilityService监测到安装界面并触发点击

安装流程

1. 系统应用安装

开机时PMS的启动流程和其它系统Service的流程是一样的:从init进程被拉起,再到zygote进程,再到SystemServer进程,进入到SystemServer.main方法后,开始初始化包含PMS在内的各大系统Service

SystemServer.run()

frameworks/base/services/java/com/android/server/SystemServer.java

// system_server 进程的入口函数
public static void main(String[] args) {
    // 注意这个run方法只是个普通的run函数,和线程自动调用的run并没有联系
    new SystemServer().run();
}

private void run() {
    ...
    try {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
        // 在这里启动PMS服务
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    ...
}

private void startBootstrapServices() {
     ...
     // 通过调用PMS的静态main方法来初始化并返回实例
     // 注意这里的main方法和SystemServer这种的main方法还是不同的,并不是由反射进行调用的
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
   ...
}

PMS.main()

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    ...
    // 包相关的处理操作将在PMS构造器中完成,整个流程很长
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    ...
    // 在ServiceManager进行注册
    ServiceManager.addService("package", m);
    return m;
}

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
     ...
     // 收集 priv-app 目录下apk信息
     final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
     scanDirTracedLI(privilegedAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR
                | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

     // 收集 app 目录下apk信息
     final File systemAppDir = new File(Environment.getRootDirectory(), "app");
     scanDirTracedLI(systemAppDir, mDefParseFlags
            | PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

     // 收集 /vendor/app 目录下apk信息
     File vendorAppDir = new File("/vendor/app");
     try {
         vendorAppDir = vendorAppDir.getCanonicalFile();
     } catch (IOException e) {
         // failed to look up canonical path, continue with original one
     }
     scanDirTracedLI(vendorAppDir, mDefParseFlags
            | PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  
     ...
}

private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir");
    try {
        scanDirLI(dir, parseFlags, scanFlags, currentTime);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
     final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
            MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;

     // 初始化一个扫描任务
     Runnable scanTask = new Runnable() {
            public void run() {
                try {
                    scanPackageTracedLI(ref_file, ref_parseFlags | 
                        PackageParser.PARSE_MUST_BE_APK, ref_scanFlags, ref_currentTime, null);
                } catch (PackageManagerException e) {
                    ...
                }
            }
        };

    // 将任务放置到线程池中进行处理
    if (dealer != null)
        dealer.addTask(scanTask);
    else
        scanTask.run();
}

private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
        int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
    try {
        return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

// 扫描apk文件方法
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
      ...
      final PackageParser.Package pkg;
    try {
        pkg = pp.parsePackage(scanFile, parseFlags);
    } catch (PackageParserException e) {
        throw PackageManagerException.from(e);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }

    ...
    return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);       
}

Package.parsePacakge()

frameworks/base/core/java/android/content/pm/PackageParser.java

public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(packageFile, flags);
    } else {
        return parseMonolithicPackage(packageFile, flags);
    }
}

private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
     ...
     // 该方法将会解析Manifest.xml文件,将apk组件信息进行保存
     final Package pkg = parseBaseApk(baseApk, assets, flags);
     ...
}

private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
        String[] outError) throws XmlPullParserException, IOException {
    ...
    return parseBaseApkCommon(pkg, null, res, parser, flags, outError);    
}

// 该方法为组件解析的核心方法,因为篇幅较长不详细分析了,无非就是解析xml文件提取出组件信息,封装成Package返回
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
        XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
        IOException {
      ...       
}

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
                                            final int policyFlags, int scanFlags, long currentTime, UserHandle user)
        throws PackageManagerException {
    ...

    // 将应用组件信息提取出来后,调用Internel方法进行应用安装
    PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
            scanFlags, currentTime, user);

    ...

    return scannedPkg;
}

private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
                                                    int policyFlags, int scanFlags, long currentTime, UserHandle user)
        throws PackageManagerException {
    ...
    // Note that we invoke the following method only if we are about to unpack an application
    PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user);
    ...        

}

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
                                            int scanFlags, long currentTime, UserHandle user) throws         PackageManagerException {
    boolean success = false;
    try {
         // 最终调用到了核心安装方法
        final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
                currentTime, user);
        success = true;
        return res;
    } finally {
        ...
    }
}

2. 通过安装器安装

PackageInstallerActivity.startInstall()

packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

private void startInstall() {
    // Start subactivity to actually install the application
    Intent newIntent = new Intent();
    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
            mPkgInfo.applicationInfo);
    newIntent.setData(mPackageURI);
    if(!TextUtils.isEmpty(mInstallFromPkgName)){
        newIntent.putExtra(InstallAppProgress.EXTRA_INSTALL_SOURCE,mInstallFromPkgName);
    }
    newIntent.putExtra(InstallAppProgress.EXTRA_NEWINSTALL,mNewInstall);
    newIntent.putExtra(AdDataHelper.INTENT_EXTRA_PI_ID, mPid);
    newIntent.setClass(this, InstallAppProgress.class);
    String installerPackageName = getIntent().getStringExtra(
            Intent.EXTRA_INSTALLER_PACKAGE_NAME);
     ...
     // 通过启动Activity到InstallAppProgress进行PMS调用
    startActivity(newIntent);
    finish();
}

InstallAppProgress.startInstall()

packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallAppProgress.java

private void startInstall() {
    ...
    // 异步进行安装
    mInstallHandler.post(new Runnable() {
        @Override
        public void run() {
            doPackageStage(pm, params);
        }
    });
}

private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
    final PackageInstaller packageInstaller = pm.getPackageInstaller();
    PackageInstaller.Session session = null;
    try {
        ...
        Intent broadcastIntent = new Intent(BROADCAST_ACTION + mInstallId);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                InstallAppProgress.this /*context*/,
                sessionId,
                broadcastIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        // binder call 到PacakgeInstallerSession进行处理
        session.commit(pendingIntent.getIntentSender());
        mInstallStartTime = SystemClock.elapsedRealtime();
    } catch (IOException e) {
        ...
    } finally {
        IoUtils.closeQuietly(session);
    }
}

PackageInstallerSesson.commit()

frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java

```java
@Override
public void commit(IntentSender statusReceiver) {
...
final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,

top Created with Sketch.