稿-Android应用安装过程

应用安装方式

  1. 系统安装,触发时机:开机时,无安装界面
  2. adb 命令安装,触发时机:adb命令行安装,无安装界面
  3. 应用市场,视市场应用的权限,有系统权限无安装界面
  4. 第三方安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。

路径1 – 系统启动过程

启动 -> AndroidRuntime -> ServerTread -> PackageManagerService -> PackageParser

PackageManagerService

/**
 * PackageManagerService的成员变量,保存所有安装包信息
 * key: pkg.applicationInfo.packageName
 * val: pkg
 */
mPackages: HashMap<String, PackageParser.Package>

/**
 * PackageManagerService的成员变量,保存所有安装包内的ContentProvider信息
 * key: ComponentName(provider.info.packageName, provider.info.name)
 * val: PackageParser.Provider
 */
mProvidersByComponent: HashMap<ComponentName, PackageParser.Provider>

mActivities: ActivityIntentResolver
mReceivers: ActivityIntentResolver

mServices: ServiceIntentResolver

路径2 – packageinstaller.apk

https://android.googlesource.com/platform/packages/apps/PackageInstaller/+/lollipop-release/

AndroidManifest.xml

PackageInstallerActivity检查各种权限,展示被安装应用相关信息,最后跳转到了实际安装应用的InstallAppProgress

InstallAppProgress又进行了一系列操作,最终把安装操作交给了PackageManager.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, installerPackageName, verificationParams, null);

注:从这一步开始,代码的运行环境已经通过Binder机制转移到了系统PackageManager运行的进程。

PackageManager.java
installPackageWithVerificationAndEncryption方法有两个,区别在于第二个参数的类型:PackageInstallObserverIPackageInstallObserver,后者对应的方法已经废弃。

PackageManager是抽象类,具体的实现在:ApplicationPackageManager

    @Override
    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                               String installerPackageName) {
        final VerificationParams verificationParams = new VerificationParams(null, null,
                null, VerificationParams.NO_UID, null);
        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                installerPackageName, verificationParams, null);
    }

installPackage把传递过来的IPackageInstallObserver包装成了LegacyPackageInstallObserver,然后把数据透传给了installCommon


    private void installCommon(Uri packageURI,
            PackageInstallObserver observer, int flags, String installerPackageName,
            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
        if (!"file".equals(packageURI.getScheme())) {
            throw new UnsupportedOperationException("Only file:// URIs are supported");
        }
        if (encryptionParams != null) {
            throw new UnsupportedOperationException("ContainerEncryptionParams not supported");
        }
        final String originPath = packageURI.getPath();
        try {
            mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
                    verificationParams, null);
        } catch (RemoteException ignored) {
        }
    }

从实现可以看到,这个方法仅支持Scheme 为file的Uri,所以InstallAppProgress在调用之前对这两种情况做了区分。这里还检查了ContainerEncryptionParams encryptionParam,不为空的情况下也抛出异常,这个没看懂。

经过上述处理后,取出安装包的路径,交给了IPackageManager.installPackage,从名字上看就能知道IPackageManager是个AIDL的接口,具体实现在PackageManagerService.java


    @Override
    public void installPackage(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride) {
        installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
                packageAbiOverride, UserHandle.getCallingUserId());
    }

这个方法没干什么,转给了installPackageAsUser处理。

    @Override
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride, int userId) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId, true, true, "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) {
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }
        verificationParams.setInstallerUid(callingUid);
        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, observer, installFlags,
                installerPackageName, verificationParams, user, packageAbiOverride);
        mHandler.sendMessage(msg);
    }

又一次进行了一系列的校验,最后获取了一个Messagemsg.what = INIT_COPYmsg.obj = new InstallParams(...),将消息发送给了mHandler

// 处理逻辑
case INIT_COPY: {
    HandlerParams params = (HandlerParams) msg.obj;
    int idx = mPendingInstalls.size();
    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) {
        // If this is the only one pending we might
        // have to bind to the service again.
        if (!connectToService()) {
            Slog.e(TAG, "Failed to bind to media container service");
            params.serviceError();
            return;
        } else {
            // Once we bind to the service, the first
            // pending request will be processed.
            mPendingInstalls.add(idx, params);
        }
    } else {
        mPendingInstalls.add(idx, params);
        // Already bound to the service. Just make
        // sure we trigger off processing the first request.
        if (idx == 0) {
            mHandler.sendEmptyMessage(MCS_BOUND);
        }
    }
        break;
}

经过一系列处理,正常情况下会把传过来的参数存入mPendingInstalls内,然后发出MCS_BOUND消息进行下一步处理。

case MCS_BOUND: {
    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
    if (msg.obj != null) {
        mContainerService = (IMediaContainerService) msg.obj;
    }
    if (mContainerService == null) {
        // Something seriously wrong. Bail out
        Slog.e(TAG, "Cannot bind to media container service");
        for (HandlerParams params : mPendingInstalls) {
            // Indicate service bind error
            params.serviceError();
        }
        mPendingInstalls.clear();
    } else if (mPendingInstalls.size() > 0) {
        HandlerParams params = mPendingInstalls.get(0);
        if (params != null) {
            if (params.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.remove(0);
                }
                if (mPendingInstalls.size() == 0) {
                    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 {
                    // 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);
                }
            }
        }
    } else {
        // Should never happen ideally.
        Slog.w(TAG, "Empty queue");
    }
    break;
}

这里实际处理复制的操作交给了params.startCopy(),这个方法在类HandlerParams里,是个final方法:

final boolean startCopy() {
    boolean res;
    try {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        if (++mRetries > MAX_RETRIES) {
            Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
            mHandler.sendEmptyMessage(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);
        res = false;
    }
    handleReturnCode();
    return res;
}

实现仅仅是包装了下重试的限制逻辑,最多重试4次,超过4次则直接失败。实际的处理逻辑由handleStartCopy()实现。handleStartCopy()是抽象方法,由子类实现。

安装参数传递过来的具体的子类为InstallParams

/*
 * 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;
    PackageInfoLite pkgLite = null;
    if (onInt && onSd) {
        // 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 {
        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                packageAbiOverride);
        /*
         * If we have too little free space, try to free cache
         * before giving up.
         */
        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);
            if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) {
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                        installFlags, packageAbiOverride);
            }
            /*
             * 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) {
        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 {
                    // Make sure the flag for installing on external
                    // media is unset
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                    installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                }
            }
        }
    }
    final InstallArgs args = createInstallArgs(this);
    mArgs = args;
    if (ret == PackageManager.INSTALL_SUCCEEDED) {
         /*
         * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
         * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
         */
        int userIdentifier = getUser().getIdentifier();
        if (userIdentifier == UserHandle.USER_ALL
                && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
            userIdentifier = UserHandle.USER_OWNER;
        }
        /*
         * 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, userIdentifier);
        if (!origin.existing && requiredUid != -1
                && isVerificationEnabled(userIdentifier, installFlags)) {
            final Intent verification = new Intent(
                    Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
            verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                    PACKAGE_MIME_TYPE);
            verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            final List<ResolveInfo> receivers = queryIntentReceivers(verification,
                    PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
                    0 /* TODO: Which userId? */);
            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 (verificationParams != null) {
                if (verificationParams.getVerificationURI() != null) {
                   verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
                         verificationParams.getVerificationURI());
                }
                if (verificationParams.getOriginatingURI() != null) {
                    verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
                          verificationParams.getOriginatingURI());
                }
                if (verificationParams.getReferrer() != null) {
                    verification.putExtra(Intent.EXTRA_REFERRER,
                          verificationParams.getReferrer());
                }
                if (verificationParams.getOriginatingUid() >= 0) {
                    verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
                          verificationParams.getOriginatingUid());
                }
                if (verificationParams.getInstallerUid() >= 0) {
                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                          verificationParams.getInstallerUid());
                }
            }
            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, getUser());
                    }
                }
            }
            final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                    mRequiredVerifierPackage, receivers);
            if (ret == PackageManager.INSTALL_SUCCEEDED
                    && mRequiredVerifierPackage != null) {
                /*
                 * 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, getUser(),
                        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 {
            /*
             * No package verification is enabled, so immediately start
             * the remote call to initiate copy using temporary file.
             */
            ret = args.copyApk(mContainerService, true);
        }
    }
    mRet = ret;
}

八卦

protected void onCreate(Bundle icicle)

《稿-Android应用安装过程》 icicle

可不可以这么推论:包名以android.**开始的为android框架的代码。以com.android.**开始的为系统服务的实现。

尝试解答

1. 管家们如何监听应用安装、卸载信息

2. 注册Receiver的过程

3. 启用/禁用组件的过程

参考资料

Android应用程序安装过程源代码分析

    原文作者:罗力
    原文地址: https://www.jianshu.com/p/1bb3f3201e05
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞