Android 8.0应用安装流程源码分析

应用安装大致有四中方式:

1,通过Adb进行安装,命令如下:

adb install xxx.apk

该命令是通过adb调用system/bin/pm脚本来生效的,命令对应的代码文件定义在commandline.cpp路径为system/core/adb/commandline.cpp

adb install命令在commandline中对应的方法是:

int adb_commandline(int argc, const char** argv) {
......
......
 while (argc > 0) {
    ......
    ......
    else if (!strcmp(argv[0], "install")) {
        if (argc < 2) return syntax_error("install requires an argument");
        if (_use_legacy_install()) {
            return install_app_legacy(argc, argv);
        }
        return install_app(argc, argv);
    }
    ......
    ......
 }

接下来会去调用system/bin/pm这个脚本,脚本代码如下:

# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/pm.jar    //设置环境变量
exec app_process $base/bin com.android.commands.pm.Pm "$@"    //$@表示传给脚本的所有参数的列表

该脚本主要功能就是通过app_process来执行pm.jar 的main函数,多说一句,在android中java程序是通过app_process启动的,可以去了解一下app_process的用法,pm.jar的main函数就相当于java进程的入口函数,

 接下来分析Pm.java:

    public static void main(String[] args) {
        int exitCode = 1;
        try {
            exitCode = new Pm().run(args);
        } catch (Exception e) {
            Log.e(TAG, "Error", e);
            System.err.println("Error: " + e);
            if (e instanceof RemoteException) {
                System.err.println(PM_NOT_RUNNING_ERR);
            }
        }
        System.exit(exitCode);
    }

main方法中new了一个Pm()对象,然后调用它的run方法:

    public int run(String[] args) throws RemoteException {
        boolean validCommand = false;
        if (args.length < 1) {
            return showUsage();
        }
        mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
        mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
        ......
        ......
        if ("install".equals(op)) {
            return runInstall();    //adb install命令对应此方法
        }
        ......
        ......
    }

runInstall又做了什么呢?

    private int runInstall() throws RemoteException {
        long startedTime = SystemClock.elapsedRealtime();
        final InstallParams params = makeInstallParams();
        final String inPath = nextArg();
        if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
            File file = new File(inPath);
            if (file.isFile()) {
                try {
                    ApkLite baseApk = PackageParser.parseApkLite(file, 0);
                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                            null, null);
                    params.sessionParams.setSize(
                            PackageHelper.calculateInstalledSize(pkgLite, false,
                            params.sessionParams.abiOverride));
                } catch (PackageParserException | IOException e) {
                    System.err.println("Error: Failed to parse APK file: " + e);
                    return 1;
                }
            } else {
                System.err.println("Error: Can't open non-file: " + inPath);
                return 1;
            }
        }

        final int sessionId = doCreateSession(params.sessionParams,
                params.installerPackageName, params.userId);

        try {
            if (inPath == null && params.sessionParams.sizeBytes == -1) {
                System.err.println("Error: must either specify a package size or an APK file");
                return 1;
            }
            if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
            Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
            if (status.second != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
            Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
                    - startedTime) + " ms");
            System.out.println("Success");
            return 0;
        } finally {
            try {
                mInstaller.abandonSession(sessionId);
            } catch (Exception ignore) {
            }
        }
    }

调用了PackageParser轻量级解析了这个文件,得到了ApkLite对象

发布了65 篇原创文章 · 获赞 17 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/lancelots/article/details/89459488