Android -- PackageManagerService APK安裝流程簡要分析

Android -- PackageManagerService APK安裝流程簡要分析


在Android系統下,我們一般會使用"adb install -r"命令來安裝應用;此時應用會被安裝到/data/app/下。這篇文章,我們就簡要分析PackageManagerService安裝apk的中間處理過程。


在進入PackageManager之前,我們先看下有關adb安裝應用的內容。在android中,adbd以後臺進程運行。當我們輸入"adb install"命令時,/syste/core/adb/目錄下commandline.cpp文件會被執行,其中adb_commandline()函數會接受該條指令,並進行處理,這裏只看install命令的執行:

int adb_commandline(int argc, const char **argv) {
......

else if (!strcmp(argv[0], "install")) {
        if (argc < 2) return usage();
        if (_use_legacy_install()) {
            return install_app_legacy(transport_type, serial, argc, argv);
        }
        return install_app(transport_type, serial, argc, argv);
    }

......
}
這裏以legacy模式爲例:
static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
    static const char *const DATA_DEST = "/data/local/tmp/%s";//安裝到data目錄下時,會將apk先拷貝一份到該目錄下
    static const char *const SD_DEST = "/sdcard/tmp/%s";//安裝到SD卡上時,會將apk先拷貝一份到/sdcard/tmp/目錄下;一般帶參數-s
    const char* where = DATA_DEST;
    int i;
    struct stat sb;

    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-s")) {
            where = SD_DEST;
        }
    }

    // Find last APK argument.
    // All other arguments passed through verbatim.
    int last_apk = -1;
    for (i = argc - 1; i >= 0; i--) {
        const char* file = argv[i];
        const char* dot = strrchr(file, '.');
        if (dot && !strcasecmp(dot, ".apk")) {
            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
                fprintf(stderr, "Invalid APK file: %s\n", file);
                return EXIT_FAILURE;
            }

            last_apk = i;
            break;
        }
    }

    if (last_apk == -1) {
        fprintf(stderr, "Missing APK file\n");
        return EXIT_FAILURE;
    }

    int result = -1;
    std::vector<const char*> apk_file = {argv[last_apk]};
    std::string apk_dest = android::base::StringPrintf(
        where, adb_basename(argv[last_apk]).c_str());
    if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;//我們即將安裝的apk文件也許會在客戶機上,這裏會先將該apk文件推送到系統的/data/local/tmp/目錄下
    argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
    result = pm_command(transport, serial, argc, argv);//執行pm腳本,進行安裝

cleanup_apk:
    delete_file(transport, serial, apk_dest);//安裝過程結束後,會清掉事先拷貝的那一份apk
    return result;
}
由於我們使用adb安裝的apk有可能會在客戶機上,所以這裏會先將apk文件拷貝一份到系統的/data/local/tmp/目錄下。然後,流程會去執行pm腳本進行安裝操作。手機的端的adbd程序接收到客戶機發送的shell pm命令後,會開啓一個shell去執行pm腳本。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 "$@"
該腳本在系統編譯時會被打包成/system/bin/pm可執行程序,執行pm可執行程序其實就是執行這段腳本。我們知道,app_process在系統啓動過程中會去啓動Zygote系統進程;同時,它也可以被用來啓動一些其他的普通進程,比如此時的pm。我們直接看啓動pm時調用的main()函數,com.android.commands.pm.Pm::main():
    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);
    }
創建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"));//IPackageManager實例,通過它可以調用到PackageManagerServcie中

        if (mPm == null) {//IPackageManager實例爲空,即返回
            System.err.println(PM_NOT_RUNNING_ERR);
            return 1;
        }
        mInstaller = mPm.getPackageInstaller();//IPackageInstaller實例,它會管理android中的應用安裝狀態

        mArgs = args;
        String op = args[0];
        mNextArg = 1;

        if ("list".equals(op)) {
            return runList();
        }

        if ("path".equals(op)) {
            return runPath();
        }

        if ("dump".equals(op)) {
            return runDump();
        }

        if ("install".equals(op)) {//此處分析的是install命令,走這條分支
            return runInstall();
        }
......
}

因爲我們傳入的是install命令,所以執行runInstall()函數;至此,安裝過程就即將進入PackageManagerService了。


同時,我們也可以調用PackageManager::installPackage()函數安裝應用,這種方式的安裝與adb install的安裝流程再走進PackageManagerService之後,都是一致地。


PackageManager的家族類圖結構如下所示:



PackageManager的功能由ApplicationPackageManager實現,ApplicationPackageManager內部持有一個指向PackageManagerService的mPM對象來傳遞函數調用。當我們調用PackageManager::installPackage()時,實際調用調用ApplicationPackageManager中的實現函數:

    @Override
    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                               String installerPackageName) {
        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                installerPackageName, mContext.getUserId());
    }

    @Override
    public void installPackage(Uri packageURI, PackageInstallObserver observer,
            int flags, String installerPackageName) {
        installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
    }

    private void installCommon(Uri packageURI,
            PackageInstallObserver observer, int flags, String installerPackageName,
            int userId) {
        if (!"file".equals(packageURI.getScheme())) {
            throw new UnsupportedOperationException("Only file:// URIs are supported");
        }

        final String originPath = packageURI.getPath();
        try {
            mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
                    userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

方法中傳入了一個PackageInstallObserver對象,它是用戶用來監聽APK安裝的最後結果的。PackageInstallObserver的定義如下:

public class PackageInstallObserver {
    private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
        @Override
        public void onUserActionRequired(Intent intent) {
            PackageInstallObserver.this.onUserActionRequired(intent);
        }

        @Override
        public void onPackageInstalled(String basePackageName, int returnCode,
                String msg, Bundle extras) {
            PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,
                    extras);
        }
    };

    /** {@hide} */
    public IPackageInstallObserver2 getBinder() {
        return mBinder;
    }

    public void onUserActionRequired(Intent intent) {
    }

    /**
     * This method will be called to report the result of the package
     * installation attempt.
     *
     * @param basePackageName Name of the package whose installation was
     *            attempted
     * @param extras If non-null, this Bundle contains extras providing
     *            additional information about an install failure. See
     *            {@link android.content.pm.PackageManager} for documentation
     *            about which extras apply to various failures; in particular
     *            the strings named EXTRA_FAILURE_*.
     * @param returnCode The numeric success or failure code indicating the
     *            basic outcome
     * @hide
     */
    public void onPackageInstalled(String basePackageName, int returnCode, String msg,
            Bundle extras) {
    }
}
其中,當apk安裝結束時,系統會回調onPackageInstalled()接口通知用戶當前apk安裝的結果信息。

接着分析APK安裝的流程,系統會調用PMS的installPackageAsUser()接口,將安裝流程帶入到PMS中:

    @Override
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, int userId) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);

        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId,
                true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");//檢查調用進程的權限

        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {//檢查指定的用戶是否被限制安裝應用
            try {
                if (observer != null) {
                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
                }
            } catch (RemoteException re) {
            }
            return;
        }

        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
            installFlags |= PackageManager.INSTALL_FROM_ADB;

        } else {
            // Caller holds INSTALL_PACKAGES permission, so we're less strict
            // about installerPackageName.

            installFlags &= ~PackageManager.INSTALL_FROM_ADB;
            installFlags &= ~PackageManager.INSTALL_ALL_USERS;
        }

        UserHandle user;
        if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {//如果帶有ISNASLL_ALL_USERS標記,則給所有用戶安裝
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }

        // Only system components can circumvent runtime permissions when installing.
        if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
                && mContext.checkCallingOrSelfPermission(Manifest.permission
                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
            throw new SecurityException("You need the "
                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
        }

        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);

        final Message msg = mHandler.obtainMessage(INIT_COPY);//要發送INIT_COPY消息,開始拷貝需要安裝的Apk
		
        final VerificationInfo verificationInfo = new VerificationInfo(
                null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);

	     //將安裝參數信息保存到InstallParams對象中
        final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
                installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
                null /*packageAbiOverride*/, null /*grantedPermissions*/,
                null /*certificates*/);
        params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;

        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));

        mHandler.sendMessage(msg);//發送消息到PackageHandler中
    }

首先是一些安裝權限檢查,之後會創建一個InstallParams實例,它裏面封裝了此次安裝APK的各項參數;接着會發送INIT_COPY消息到Handler進行處理。

我們先總體看一下PMS應用安裝過程中會涉及到的一些類型:


這些類型的作用就是封裝一次應用安裝過程的一些基本信息,我們只要注意它們的使用場景即可。INIT_COPY消息會觸發APK文件的拷貝動作,它會由PMS::PackageHandler接收,而PackageHandler在PMS初始化時會被創建。PackageHandler主要負責這些APK安裝消息的接收處理。我們先看INIT_COPY消息的處理過程:

                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;//獲取Apk安裝參數
                    int idx = mPendingInstalls.size();//mPendingInstalls保存所有的需要安裝的APk的安裝信息
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                    // If a bind was already initiated we dont really
                    // need to do anything. The pending install
                    // will be processed later on.
                    if (!mBound) {//如果沒有綁定DefaultContainerService服務;服務連接成功後,會置爲true
                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                        // If this is the only one pending we might
                        // have to bind to the service again.
                        if (!connectToService()) {//異步過程.去綁定DefaultContainerService服務,綁定失敗,需要報告錯誤信息;綁定成功後,會發送MCS_BOUND消息
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                    System.identityHashCode(mHandler));
                            if (params.traceMethod != null) {
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
                                        params.traceCookie);
                            }
                            return;
                        } else {//綁定服務成功後,將當前的安裝參數請求保存到mPendingInstalls
                            // Once we bind to the service, the first
                            // pending request will be processed.
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                        mPendingInstalls.add(idx, params);//服務已經綁定,也會將安裝信息保存到mPendingInstalls中
                        // Already bound to the service. Just make
                        // sure we trigger off processing the first request.
                        if (idx == 0) {//如果mPendingInstalls中只有一項內容,則立即發送MCS_BOUND消息
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
                }
mPendingInstalls是PackageHandler的一個成員,它保存所有的APK安裝的InstallParams對象。mBound標識當前有沒有綁定DefaultContainerService服務,之後的安裝流程會調用它的一些方法。綁定DCS服務的處理由PackageHandler::connectToService()函數提供:
    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
            DEFAULT_CONTAINER_PACKAGE,
            "com.android.defcontainer.DefaultContainerService");

    final private DefaultContainerConnection mDefContainerConn =
            new DefaultContainerConnection();
    class DefaultContainerConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
            IMediaContainerService imcs =
                IMediaContainerService.Stub.asInterface(service);
            mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
        }

        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
        }
    }

        private boolean connectToService() {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
                    " DefaultContainerService");
            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
            if (mContext.bindServiceAsUser(service, mDefContainerConn,
                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                mBound = true;
                return true;
            }
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            return false;
        }
如果服務綁定成功,mBound會置爲true,並會發送MCS_BOUND消息,並附帶DCS服務的Binder實例發送給PackageHandler。


接着看MCS_BOUND消息的處理:

                case MCS_BOUND: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;//DefaultContainerService服務的代理
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                    }
                    if (mContainerService == null) {
                        if (!mBound) {//如果服務沒有連接成功,則需要報告錯誤
                            // Something seriously wrong since we are not bound and we are not
                            // waiting for connection. Bail out.
                            Slog.e(TAG, "Cannot bind to media container service");
                            for (HandlerParams params : mPendingInstalls) {
                                // Indicate service bind error
                                params.serviceError();
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                        System.identityHashCode(params));
                                if (params.traceMethod != null) {
                                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
                                            params.traceMethod, params.traceCookie);
                                }
                                return;
                            }
                            mPendingInstalls.clear();//情況mPendingInstalls
                        } else {
                            Slog.w(TAG, "Waiting to connect to media container service");
                        }
                    } else if (mPendingInstalls.size() > 0) {//DefaultContainerService服務連接正常
                        HandlerParams params = mPendingInstalls.get(0);//從首部拿出需要執行的安裝參數信息
                        if (params != null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                    System.identityHashCode(params));
                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                            if (params.startCopy()) {//調用HandlerParrams接口,去執行apk的拷貝工作;此處是調用HandlerParrams::startCopy()
                                // We are done...  look for more work or to
                                // go idle.
                                if (DEBUG_SD_INSTALL) Log.i(TAG,
                                        "Checking for more work or unbind...");
                                // Delete pending install
                                if (mPendingInstalls.size() > 0) {//工作完成,移除mPendingInstalls首部內容,因爲我們是從首部開始執行的
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {//如果mPendingInstalls已經沒有內容,說明安裝任務已經全部執行完畢,則會延遲10s後斷開服務連接
                                    if (mBound) {
                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
                                                "Posting delayed MCS_UNBIND");
                                        removeMessages(MCS_UNBIND);
                                        Message ubmsg = obtainMessage(MCS_UNBIND);
                                        // Unbind after a little delay, to avoid
                                        // continual thrashing.
                                        sendMessageDelayed(ubmsg, 10000);
                                    }
                                } else {//否則,會再次發送MCS_BOUND消息,處理下一個安裝請求
                                    // There are more pending requests in queue.
                                    // Just post MCS_BOUND message to trigger processing
                                    // of next pending install.
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next work");
                                    mHandler.sendEmptyMessage(MCS_BOUND);//發送消息,處理下一個安裝請求
                                }
                            }
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }
mContainerService對象保存了DefaultContainerService服務的Binder實例,它將被用來調用一些該服務中提供的方法。如果該實例爲空,則表明服務連接異常,則需要對外報告錯誤,並清空mPendingInstalls集合;如果非空,則要處理APK的安裝請求:

  • 從mPendingInstalls首部取出要處理的安裝參數對象,並調用InstallParams::startCopy()函數,開始進行APK的拷貝工作
  • 如果拷貝工作完成,則會移除mPendingInstalls首部的對象
  • 如果此時mPendingInstalls隊列爲空,表明所有的請求已經處理完了;則會通過發送MCS_UNBIND消息,延遲10s去斷開與DCS服務的連接
  • 如果此時mPendingInstalls對比不爲空,表明當前還有安裝請求需要處理,則會再次發送MCS_BOUND消息;進行新一輪的安裝處理流程

因爲傳入的安裝參數對象是InstallParams,根據之前的圖示,我們直接看它父類的HandlerParams::startCopy()函數:

        final boolean startCopy() {
            boolean res;
            try {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

                if (++mRetries > MAX_RETRIES) {//會嘗試安裝4次,如果4次都沒有安裝成功,則會退出
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);//嘗試4次後,都沒有安裝成功,則發送MCS_GIVE_UP消息放棄這次安裝請求
                    handleServiceError();
                    return false;
                } else {
                    handleStartCopy();
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);//安裝出錯,則發送消息MCS_RECONNECT消息重新連接
                res = false;
            }
            handleReturnCode();
            return res;
        }
HandlerParams::startCopy()爲HandlerParams的子類所共有。首先一次apk的安裝操作總共會嘗試四次,如果四次都安裝失敗,則會發送MCS_GIVE_UP消息,放棄這次安裝請求,並調用子類實現的handleServiceError()處理錯誤,然後直接返回;否則,調用子類實現的handleStartCopy()函數進程copy流程。handleStartCopy()處理成功後,還會調用子類實現的handleReturnCode()處理最後的結果。我們看InstallParams::handleStartCopy()的實現:
        /*
         * Invoke remote method to get package information and install
         * location values. Override install location based on default
         * policy if needed and then create install arguments based
         * on the install location.
         */
        public void handleStartCopy() throws RemoteException {
            int ret = PackageManager.INSTALL_SUCCEEDED;

            // If we're already staged, we've firmly committed to an install location
            if (origin.staged) {
                if (origin.file != null) {
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                    installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                } else if (origin.cid != null) {
                    installFlags |= PackageManager.INSTALL_EXTERNAL;
                    installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else {
                    throw new IllegalStateException("Invalid stage location");
                }
            }

            final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
            final boolean ephemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
            PackageInfoLite pkgLite = null;

            if (onInt && onSd) {//如果既有安裝在內部的標誌,又有安裝SD卡上的標誌,則設置錯誤返回 
                // Check if both bits are set.
                Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else if (onSd && ephemeral) {//此處與上述類似
                Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);//獲取安裝包包含有應用信息的PacageInfoLite對象

                if (DEBUG_EPHEMERAL && ephemeral) {
                    Slog.v(TAG, "pkgLite for install: " + pkgLite);
                }

                /*
                 * If we have too little free space, try to free cache
                 * before giving up.
                 */
                 //如果安裝的位置空間不夠,會先嚐試清除cache空間
                if (!origin.staged && pkgLite.recommendedInstallLocation
                        == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    // TODO: focus freeing disk space on the target device
                    final StorageManager storage = StorageManager.from(mContext);
                    final long lowThreshold = storage.getStorageLowBytes(
                            Environment.getDataDirectory());

                    final long sizeBytes = mContainerService.calculateInstalledSize(
                            origin.resolvedPath, isForwardLocked(), packageAbiOverride);

                    try {
                        mInstaller.freeCache(null, sizeBytes + lowThreshold);
                        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                                installFlags, packageAbiOverride);
                    } catch (InstallerException e) {
                        Slog.w(TAG, "Failed to free cache", e);
                    }

                    /*
                     * The cache free must have deleted the file we
                     * downloaded to install.
                     *
                     * TODO: fix the "freeCache" call to not delete
                     *       the file we care about.
                     */
                    if (pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                    }
                }
            }

            if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果該標誌位依然是INSTALL_SUCCEEDED,則說明前面的校驗都通過
                int loc = pkgLite.recommendedInstallLocation;
                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                    ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                } else {
                    // Override with defaults if needed.
                    loc = installLocationPolicy(pkgLite);
                    if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                        ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                    } else if (!onSd && !onInt) {
                        // Override install location with flags
                        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                            // Set the flag to install on external media.
                            installFlags |= PackageManager.INSTALL_EXTERNAL;
                            installFlags &= ~PackageManager.INSTALL_INTERNAL;
                        } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
                            if (DEBUG_EPHEMERAL) {
                                Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                            }
                            installFlags |= PackageManager.INSTALL_EPHEMERAL;
                            installFlags &= ~(PackageManager.INSTALL_EXTERNAL
                                    |PackageManager.INSTALL_INTERNAL);
                        } else {
                            // Make sure the flag for installing on external
                            // media is unset
                            installFlags |= PackageManager.INSTALL_INTERNAL;
                            installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                        }
                    }
                }
            }

            final InstallArgs args = createInstallArgs(this);//函數中會有分支處理,這裏考慮FileInstallArgs實例創建情況,並會保存一份到InstallParams::mArgs
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果該標誌位依然是INSTALL_SUCCEEDED,則說明前面的校驗都通過
                // TODO: http://b/22976637
                // Apps installed for "all" users use the device owner to verify the app
                UserHandle verifierUser = getUser();
                if (verifierUser == UserHandle.ALL) {
                    verifierUser = UserHandle.SYSTEM;
                }

                /*
                 * Determine if we have any installed package verifiers. If we
                 * do, then we'll defer to them to verify the packages.
                 */
                final int requiredUid = mRequiredVerifierPackage == null ? -1
                        : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
                                verifierUser.getIdentifier());
				//if部分是一段執行應用校驗的代碼,如果需要校驗,則通過向系統中所有帶有校驗功能的組件發送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION廣播來完成
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
                    final Intent verification = new Intent(
                            Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                    verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                    verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                            PACKAGE_MIME_TYPE);
                    verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    // Query all live verifiers based on current user state
                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());

                    if (DEBUG_VERIFY) {
                        Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
                                + verification.toString() + " with " + pkgLite.verifiers.length
                                + " optional verifiers");
                    }

                    final int verificationId = mPendingVerificationToken++;

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
                            installerPackageName);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
                            installFlags);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
                            pkgLite.packageName);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                            pkgLite.versionCode);

                    if (verificationInfo != null) {
                        if (verificationInfo.originatingUri != null) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
                                    verificationInfo.originatingUri);
                        }
                        if (verificationInfo.referrer != null) {
                            verification.putExtra(Intent.EXTRA_REFERRER,
                                    verificationInfo.referrer);
                        }
                        if (verificationInfo.originatingUid >= 0) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
                                    verificationInfo.originatingUid);
                        }
                        if (verificationInfo.installerUid >= 0) {
                            verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                                    verificationInfo.installerUid);
                        }
                    }

                    final PackageVerificationState verificationState = new PackageVerificationState(
                            requiredUid, args);

                    mPendingVerification.append(verificationId, verificationState);

                    final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                            receivers, verificationState);

                    /*
                     * If any sufficient verifiers were listed in the package
                     * manifest, attempt to ask them.
                     */
                    if (sufficientVerifiers != null) {
                        final int N = sufficientVerifiers.size();
                        if (N == 0) {
                            Slog.i(TAG, "Additional verifiers required, but none installed.");
                            ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                        } else {
                            for (int i = 0; i < N; i++) {
                                final ComponentName verifierComponent = sufficientVerifiers.get(i);

                                final Intent sufficientIntent = new Intent(verification);
                                sufficientIntent.setComponent(verifierComponent);
                                mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                            }
                        }
                    }

                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                            mRequiredVerifierPackage, receivers);
                    if (ret == PackageManager.INSTALL_SUCCEEDED
                            && mRequiredVerifierPackage != null) {
                        Trace.asyncTraceBegin(
                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
                        /*
                         * Send the intent to the required verification agent,
                         * but only start the verification timeout after the
                         * target BroadcastReceivers have run.
                         */
                        verification.setComponent(requiredVerifierComponent);
                        mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                                new BroadcastReceiver() {
                                    @Override
                                    public void onReceive(Context context, Intent intent) {
                                        final Message msg = mHandler
                                                .obtainMessage(CHECK_PENDING_VERIFICATION);
                                        msg.arg1 = verificationId;
                                        mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                                    }
                                }, null, 0, null, null);

                        /*
                         * We don't want the copy to proceed until verification
                         * succeeds, so null out this field.
                         */
                        mArgs = null;
                    }
                } else {//不需要校驗,則調用FileInstallArgs::copyApk()繼續後續的處理
                    /*
                     * No package verification is enabled, so immediately start
                     * the remote call to initiate copy using temporary file.
                     */
                    ret = args.copyApk(mContainerService, true);
                }
            }

            mRet = ret;
        }
這裏總結下這段代碼處理:

  • 首先會進行一些安裝標誌的判斷
  • 調用DCS::getMinimalPackageInfo()方法獲取該apk安裝需要的大小及其他信息,信息會封裝到PackageInfoLite對象中
  • 如果檢測到當前的目錄下的大小不足以安裝應用,還回去進行cache的清理工作
  • 隨後會以當前的InstallParams實例,創建FileInstallArgs對象,並保存一份到InstallParams對象的mArgs字段中
  • 後續是一段組件校驗工作,這裏不做分析
  • 最後FileInstallArgs::copyApk()函數,進行下一步處理

接着看FileInstallArgs::copyApk()函數:

        private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
            if (origin.staged) {
                if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
                codeFile = origin.file;
                resourceFile = origin.file;
                return PackageManager.INSTALL_SUCCEEDED;
            }

            try {
                final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
                final File tempDir =
                        mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//通過PackageInstallService在/data/app/下生成臨時文件
                codeFile = tempDir;
                resourceFile = tempDir;
            } catch (IOException e) {
                Slog.w(TAG, "Failed to create copy file: " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }

			
			//爲臨時文件目錄創建ParcelFileDescriptor描述符,它能在Binder間傳遞
            final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
                @Override
                public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
                    if (!FileUtils.isValidExtFilename(name)) {
                        throw new IllegalArgumentException("Invalid filename: " + name);
                    }
                    try {
                        final File file = new File(codeFile, name);
                        final FileDescriptor fd = Os.open(file.getAbsolutePath(),
                                O_RDWR | O_CREAT, 0644);
                        Os.chmod(file.getAbsolutePath(), 0644);
                        return new ParcelFileDescriptor(fd);
                    } catch (ErrnoException e) {
                        throw new RemoteException("Failed to open: " + e.getMessage());
                    }
                }
            };

            int ret = PackageManager.INSTALL_SUCCEEDED;

			//使用DefaultContainerService::copyPackage()方法執行apk文件的複製
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.e(TAG, "Failed to copy package");
                return ret;
            }

			//安裝應用中存在的native動態庫,主要是從Apk打包文件中將它們提取出來放置
            final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
            NativeLibraryHelper.Handle handle = null;
            try {
                handle = NativeLibraryHelper.Handle.create(codeFile);
                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                        abiOverride);
            } catch (IOException e) {
                Slog.e(TAG, "Copying native libraries failed", e);
                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
            } finally {
                IoUtils.closeQuietly(handle);
            }

            return ret;
        }
這裏的處理有如下幾個:

  • 通過PackageInstallService爲要安裝的apk在/data/app/下生成一個零時文件tempDir,它的命名並不以.apk結尾
  • 爲該tempDir創建IParcelFileDescriptorFactory文件描述符,它可以在進程間傳遞
  • 調用DefaultContainerService::copyPackage()方法執行apk臨時文件的複製
  • 最後再將apk中包含的一些庫文件提取出來,放置到對應的lib/目錄下

生成apk臨時文件的調用是PackageInstallService::allocateStageDirLegacy():

    @Deprecated
    public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
        synchronized (mSessions) {
            try {
                final int sessionId = allocateSessionIdLocked();
                mLegacySessions.put(sessionId, true);
                final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
                prepareStageDir(stageDir);
                return stageDir;
            } catch (IllegalStateException e) {
                throw new IOException(e);
            }
        }
    }

    private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
        final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
        return new File(stagingDir, "vmdl" + sessionId + ".tmp");
    }
臨時文件的名稱格式大致是:'vmdl-隨機數.tmp'的形式。

如果一切過程都正常,至此,APK安裝的第一部分的工做:APK文件的拷貝,就結束了;根據前面的流程,最後會調用InstallParams::handleReturnCode()執行返回結果的處理:

        @Override
        void handleReturnCode() {
            // If mArgs is null, then MCS couldn't be reached. When it
            // reconnects, it will try again to install. At that point, this
            // will succeed.
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
        }
因爲InstallParams::mArgs我們之前賦值過,所以肯定不爲空;繼續調用processPendingInstall()函數:
    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);//消息移除,防止此處被重複調用
                 // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.setReturnCode(currentStatus);
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = null;
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果之前的處理順利完成
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageTracedLI(args, res);//則需要去解析、裝載應用
                    }
                    args.doPostInstall(res.returnCode, res.uid);
                }

                // A restore should be performed at this point if (a) the install
                // succeeded, (b) the operation is not an update, and (c) the new
                // package has not opted out of backup participation.
                //後面一段都在執行備份操作
                final boolean update = res.removedInfo != null
                        && res.removedInfo.removedPackage != null;
                final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
                boolean doRestore = !update
                        && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);

                // Set up the post-install work request bookkeeping.  This will be used
                // and cleaned up by the post-install event handling regardless of whether
                // there's a restore pass performed.  Token values are >= 1.
                int token;
                if (mNextInstallToken < 0) mNextInstallToken = 1;
                token = mNextInstallToken++;

                PostInstallData data = new PostInstallData(args, res);
                mRunningInstalls.put(token, data);
                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);

                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
                    // Pass responsibility to the Backup Manager.  It will perform a
                    // restore if appropriate, then pass responsibility back to the
                    // Package Manager to run the post-install observer callbacks
                    // and broadcasts.
                    IBackupManager bm = IBackupManager.Stub.asInterface(
                            ServiceManager.getService(Context.BACKUP_SERVICE));
                    if (bm != null) {
                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                + " to BM for possible restore");
                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                        try {
                            // TODO: http://b/22388012
                            if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
                                bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
                            } else {
                                doRestore = false;
                            }
                        } catch (RemoteException e) {
                            // can't happen; the backup manager is local
                        } catch (Exception e) {
                            Slog.e(TAG, "Exception trying to enqueue restore", e);
                            doRestore = false;
                        }
                    } else {
                        Slog.e(TAG, "Backup Manager not found!");
                        doRestore = false;
                    }
                }

                if (!doRestore) {//直接去處理安裝請求
                    // No restore possible, or the Backup Manager was mysteriously not
                    // available -- just fire the post-install work request directly.
                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);

                    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);

                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);//此處發送POST_INSTALL消息,繼續處理流程
                    mHandler.sendMessage(msg);
                }
            }
        });
    }
函數內會調用FileInstallArgs的doPreInstall()/doPostInstall()函數進行一些清理工作。其中PMS::installPackageTracedLI()函數的主要功能就是將當前安裝的apk加入到它的管理體系中,以便之後統一管理;特殊的,該函數內部會調用FileInstallArgs::doReanme()函數將之前的apk備份文件重命名。具體的實現是掃描APK的過程,這部分之前已經有介紹過。略去之後的備份工作後,最後會發送POST_INSTALL消息,依舊是PackageHandler處理:
case POST_INSTALL: {//應用安裝的收尾處理:主要動作是發送廣播,通知系統中其他應用,開始某些處理工作:如果Launcher添加應用圖標等
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);

                    PostInstallData data = mRunningInstalls.get(msg.arg1);
                    final boolean didRestore = (msg.arg2 != 0);
                    mRunningInstalls.delete(msg.arg1);

                    if (data != null) {
                        InstallArgs args = data.args;
                        PackageInstalledInfo parentRes = data.res;

                        final boolean grantPermissions = (args.installFlags
                                & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
                        final boolean killApp = (args.installFlags
                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                        final String[] grantedPermissions = args.installGrantPermissions;

                        // Handle the parent package
                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
                                grantedPermissions, didRestore, args.installerPackageName,
                                args.observer);//各種廣播的發送處理

                        // Handle the child packages
                        final int childCount = (parentRes.addedChildPackages != null)
                                ? parentRes.addedChildPackages.size() : 0;
                        for (int i = 0; i < childCount; i++) {
                            PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
                            handlePackagePostInstall(childRes, grantPermissions, killApp,
                                    grantedPermissions, false, args.installerPackageName,
                                    args.observer);
                        }

                        // Log tracing if needed
                        if (args.traceMethod != null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
                                    args.traceCookie);
                        }
                    } else {
                        Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                    }

                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
                } break;
由於需要安裝的apk文件已經拷貝到了系統中,並且PMS也已經對它進行了統一管理;到此,APK的安裝工作就基本完成了。但是,此時系統其它組件並不知道此時有新的APK安裝進了系統中,所以這裏需要發送一些廣播給感興趣的接收者,通知它們當前有新的apk安裝完成了。這一部分最明顯的就是Launcher了,我們安裝apk後,Launcher上要添加圖標,就是根據這部分內容來的。發送廣播的主要函數是handlePackagePostInstall(),它的實現如下:
    private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            // Send the removed broadcasts
            if (res.removedInfo != null) {
                res.removedInfo.sendPackageRemovedBroadcasts(killApp);
            }

            // Now that we successfully installed the package, grant runtime
            // permissions if requested before broadcasting the install.
            if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
                    >= Build.VERSION_CODES.M) {
                grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
            }

            final boolean update = res.removedInfo != null
                    && res.removedInfo.removedPackage != null;

            // If this is the first time we have child packages for a disabled privileged
            // app that had no children, we grant requested runtime permissions to the new
            // children if the parent on the system image had them already granted.
            if (res.pkg.parentPackage != null) {
                synchronized (mPackages) {
                    grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
                }
            }

            synchronized (mPackages) {
                mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
            }

            final String packageName = res.pkg.applicationInfo.packageName;
            Bundle extras = new Bundle(1);
            extras.putInt(Intent.EXTRA_UID, res.uid);

            // Determine the set of users who are adding this package for
            // the first time vs. those who are seeing an update.
            int[] firstUsers = EMPTY_INT_ARRAY;
            int[] updateUsers = EMPTY_INT_ARRAY;
            if (res.origUsers == null || res.origUsers.length == 0) {
                firstUsers = res.newUsers;
            } else {
                for (int newUser : res.newUsers) {
                    boolean isNew = true;
                    for (int origUser : res.origUsers) {
                        if (origUser == newUser) {
                            isNew = false;
                            break;
                        }
                    }
                    if (isNew) {
                        firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
                    } else {
                        updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
                    }
                }
            }

            // Send installed broadcasts if the install/update is not ephemeral
            if (!isEphemeral(res.pkg)) {
                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);

                // Send added for users that see the package for the first time
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/, null /*targetPackage*/,
                        null /*finishedReceiver*/, firstUsers);//首先要發送Intent.ACTION_PACKAGE_ADDED廣播,表明系統中有新的apk被安裝了

                // Send added for users that don't see the package for the first time
                if (update) {
                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
                }
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/, null /*targetPackage*/,
                        null /*finishedReceiver*/, updateUsers);

                // Send replaced for users that don't see the package for the first time
                if (update) {//如果當前安裝是升級,則還需要發送更多的廣播:Intent.ACTION_PACKAGE_REPLACED/Intent.ACTION_MY_PACKAGE_REPLACED
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                            packageName, extras, 0 /*flags*/,
                            null /*targetPackage*/, null /*finishedReceiver*/,
                            updateUsers);
                    sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                            null /*package*/, null /*extras*/, 0 /*flags*/,
                            packageName /*targetPackage*/,
                            null /*finishedReceiver*/, updateUsers);
                } else if (launchedForRestore && !isSystemApp(res.pkg)) {
                    // First-install and we did a restore, so we're responsible for the
                    // first-launch broadcast.
                    if (DEBUG_BACKUP) {
                        Slog.i(TAG, "Post-restore of " + packageName
                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
                    }
                    sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
                }

                // Send broadcast package appeared if forward locked/external for all users
                // treat asec-hosted packages like removable media on upgrade
                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {//如果安裝的是foreword lock應用或是安裝在SD卡上的應用,也有相關的廣播要發送
                    if (DEBUG_INSTALL) {
                        Slog.i(TAG, "upgrading pkg " + res.pkg
                                + " is ASEC-hosted -> AVAILABLE");
                    }
                    final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
                    ArrayList<String> pkgList = new ArrayList<>(1);
                    pkgList.add(packageName);
                    sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
                }
            }

            // Work that needs to happen on first install within each user
            if (firstUsers != null && firstUsers.length > 0) {
                synchronized (mPackages) {
                    for (int userId : firstUsers) {
                        // If this app is a browser and it's newly-installed for some
                        // users, clear any default-browser state in those users. The
                        // app's nature doesn't depend on the user, so we can just check
                        // its browser nature in any user and generalize.
                        if (packageIsBrowser(packageName, userId)) {
                            mSettings.setDefaultBrowserPackageNameLPw(null, userId);
                        }

                        // We may also need to apply pending (restored) runtime
                        // permission grants within these users.
                        mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
                    }
                }
            }

            // Log current value of "unknown sources" setting
            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                    getUnknownSourcesSettings());

            // Force a gc to clear up things
            Runtime.getRuntime().gc();

            // Remove the replaced package's older resources safely now
            // We delete after a gc for applications  on sdcard.
            if (res.removedInfo != null && res.removedInfo.args != null) {
                synchronized (mInstallLock) {
                    res.removedInfo.args.doPostDeleteLI(true);
                }
            }
        }

        // If someone is watching installs - notify them
        if (installObserver != null) {//回調接口調用,反饋最終安裝的結果
            try {
                Bundle extras = extrasForInstallResult(res);
                installObserver.onPackageInstalled(res.name, res.returnCode,
                        res.returnMsg, extras);
            } catch (RemoteException e) {
                Slog.i(TAG, "Observer no longer exists.");
            }
        }
    }
主要處理就是發送各種廣播,例如:

  • Intent.ACTION_PACKAGE_ADDED:通知系統其它組件,當前有新的apk安裝成功了,例如Launcher;Launcher再去向PMS查詢所有帶有主Activity的應用信息,更新顯示。

最後再通過用戶註冊的Observer回調對象將安裝結果回調給監聽者。


分析到這裏,一個APK的安裝過程就簡要地分析完成了。


發佈了72 篇原創文章 · 獲贊 68 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章