PackageManagerService安装APK流程

来源:互联网 发布:淘宝低价风险交易 编辑:程序博客网 时间:2024/04/29 13:01

     Android手机安装APK有几种方式

通过ADB安装

通过应用商店安装

通过把APK放在手机目录,手动安装,这种安装方式有安装界面

      这三种安装方式都是调用了PKMS的借口,到PKMS后流程都是相同的,这里主要介绍下通过应用商店安装APK的流程。从应用商店下载APK后会调用PackageManagerService的installPackage()方法,安装流程如下:


1.   installPackage方法中获取安装APK的userId,然后调用installPackageAsUser()

    @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());    }

2.   installPackageAsUser()主要进行一些权限的检查,首先检查调用安装的进程是否有安装应用的权限,再检查调用进程的所属用户是否有权限安装应用,检查完成之后,把安装参数保存在installParams对象中,然后发送INIT_COPY消息。

    @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);        }        // 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");        }        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, null, observer, installFlags, installerPackageName,                null, verificationParams, user, packageAbiOverride, null);        mHandler.sendMessage(msg);    }

3.  在INIT_COPY消息的处理中将绑定DefaultContainerService,因为这是一个异步的过程,要等待绑定的结果通过onServiceConnected()返回,所以,这里将安装的参数信息放到mPendingInstalls列表中。如果这个service以前就绑定好了,现在不在需要再绑定,安装信息也会先放到mPendingInstalls中。如果有多个安装请求同时到达,通过mPendingInstalls列表可以对它们进行排队。如果列表中只有一项,说明没有更多的安装请求,此时会立即发送MCS_BOUND消息,进入下一步的处理。而onServiceConnected()方法的处理同样是发送MCS_BOUND消息

                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;                }

4.  MCS_BOUND消息的处理过程就是调用InstallParams类的startCopy()方法来执行安装。并会判断mPendingInstalls是否仍有需要安装的应用,有的话再次发送MCS_BOUND消息,没有的话则发送MCS_UNBIND消息,和DefaultContainerService解除绑定。

 case MCS_BOUND: {                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");                    if (msg.obj != null) {                        mContainerService = (IMediaContainerService) msg.obj;                    }                    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();                            }                            mPendingInstalls.clear();                        } else {                            Slog.w(TAG, "Waiting to connect to media container service");                        }                    } 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;                }


安装参数InstallParams类结构与继承关系如下:

     4.1 Handlerarams有3个子类,分别是InstallParams、MoveParams、MeatureParams,其中,InstallParams用于处理APK的安装、MoveParams用于处理APK的移动,例如从SD卡移到内部存储,MeasureParams用于查询APK占据存储空间的大小。

     4.2 InstallParams内部有一个安装参数InstallArgs(后面会有用到),InstallArgs有两个派生类,FileInstallArgs和SdInstallArgs,分别代表在内部安装APK和在SD卡安装APK。






5. 继续分析InstallParams类的startCopy()方法,由于InstallParams没有重写startCopy()方法,因此调用其父类HandlerParamsstartCopy()方法,如下:

        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;        }

6.  startCopy()中调用了InstallParams类实现的handleStartCopy()handleReturnCode(),handleStartCopy()主要是把APK复制到指定路径,handleReturnCode()则对APK进行安装处理。

7. handleStartCopy()方法如下

   7.1 调用DefaultContainerService的getMinimalPackageInfo函数,获取PackageInfoLite对象,这是一个轻量级的描述APK结构的对象,在这里,主要想获取recommendedInstallLocation变量,即推荐的安装路径。

  7.2调用installLocationPolicy对安装路径进行检查,确认最终的安装路径。

  7.3 调用createInstallArgs创建安装参数,若安装在内部存储,则返回FileInstallArgs,若安装在sd卡,则返回SdInstallArgs

  7.4然后调用其安装参数的copyApk进行APK的拷贝

 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(null, 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.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);                    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);                    // Apps installed for "all" users use the device owner to verify the app                    UserHandle verifierUser = getUser();                    if (verifierUser == UserHandle.ALL) {                        verifierUser = UserHandle.OWNER;                    }                    /*                     * 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) {                        /*                         * 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 {                    /*                     * No package verification is enabled, so immediately start                     * the remote call to initiate copy using temporary file.                     */                    ret = args.copyApk(mContainerService, true);                }            }            mRet = ret;        }

8. 这里以安装在内部存储为例进行讲解,copyAPK()如下:

     8.1 调用PackageInstallerService的allocateInternalStageDirLegacydata/app下生成临时文件。

     8.2 使用服务DefaultContainerServicecopyPackage()方法复制文件 到data/app下

     8.3 安装应用中自带的native的动态库 

 int copyApk(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 File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid);                codeFile = tempDir;                resourceFile = tempDir;            } catch (IOException e) {                Slog.w(TAG, "Failed to create copy file: " + e);                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;            }            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;            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);            if (ret != PackageManager.INSTALL_SUCCEEDED) {                Slog.e(TAG, "Failed to copy package");                return ret;            }            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;        }

9. 到这一步,copy APK的工作已经完成。下一步是进行APK的处理,即安装APK,调用的是FileInstallArgshandleReturnCode()方法。handleReturnCode()方法只是调用了processpendingInstall()方法,如下:

        @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);            }        }

10.processpendingInstall()方法如下:

    10.1调用参数InstallArgsdoPreInstall()函数,如没安装成功,则做一些清理工作,如删除创建的目录。

        int doPreInstall(int status) {            if (status != PackageManager.INSTALL_SUCCEEDED) {//清除创建的目录                cleanUp();            }            return status;        }

    10.2调用installPackageLI()进行APK的安装

    10.3调用参数InstallArgsdoPostInstall()函数,如没安装成功,则做一些清理工作,如删除创建的目录。

    10.4完成以上步骤表示安装已经完成了,向mHandler发送一个POST_INSTALL消息

 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.returnCode = currentStatus;                res.uid = -1;                res.pkg = null;                res.removedInfo = new PackageRemovedInfo();                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {                    args.doPreInstall(res.returnCode);                    synchronized (mInstallLock) {                        installPackageLI(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.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");                        try {                            if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {                                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);                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);                    mHandler.sendMessage(msg);                }            }        });    }

11.分析具体的安装函数installPackage(),如下,

    11.1调用PackageParser.parsePackage解析APK文件,得到含有APK信息的PackageParser.Packgae对象

    11.2根据获取的PackageParser.Packgae对象判断APK是升级还是安装新的应用,若为更新应用,则调用replacePackageLI(),若为安装新的应用,则调用installNewPackageLI()

   private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {        final int installFlags = args.installFlags;        final String installerPackageName = args.installerPackageName;        final String volumeUuid = args.volumeUuid;        final File tmpPackageFile = new File(args.getCodePath());        final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);        final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)                || (args.volumeUuid != null));        boolean replace = false;        int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;        if (args.move != null) {            // moving a complete application; perfom an initial scan on the new install location            scanFlags |= SCAN_INITIAL;        }        // Result object to be returned        res.returnCode = PackageManager.INSTALL_SUCCEEDED;        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);        // Retrieve PackageSettings and parse package        final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY                | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)                | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);        PackageParser pp = new PackageParser();        pp.setSeparateProcesses(mSeparateProcesses);        pp.setDisplayMetrics(mMetrics);        final PackageParser.Package pkg;        try {            pkg = pp.parsePackage(tmpPackageFile, parseFlags);        } catch (PackageParserException e) {            res.setError("Failed parse during installPackageLI", e);            return;        }        // Mark that we have an install time CPU ABI override.        pkg.cpuAbiOverride = args.abiOverride;        String pkgName = res.name = pkg.packageName;        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {            if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {                res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");                return;            }        }        try {            pp.collectCertificates(pkg, parseFlags);            pp.collectManifestDigest(pkg);        } catch (PackageParserException e) {            res.setError("Failed collect during installPackageLI", e);            return;        }        /* If the installer passed in a manifest digest, compare it now. */        if (args.manifestDigest != null) {            if (DEBUG_INSTALL) {                final String parsedManifest = pkg.manifestDigest == null ? "null"                        : pkg.manifestDigest.toString();                Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "                        + parsedManifest);            }            if (!args.manifestDigest.equals(pkg.manifestDigest)) {                res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");                return;            }        } else if (DEBUG_INSTALL) {            final String parsedManifest = pkg.manifestDigest == null                    ? "null" : pkg.manifestDigest.toString();            Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);        }        // Get rid of all references to package scan path via parser.        pp = null;        String oldCodePath = null;        boolean systemApp = false;        synchronized (mPackages) {            // Check if installing already existing package            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {                String oldName = mSettings.mRenamedPackages.get(pkgName);                if (pkg.mOriginalPackages != null                        && pkg.mOriginalPackages.contains(oldName)                        && mPackages.containsKey(oldName)) {                    // This package is derived from an original package,                    // and this device has been updating from that original                    // name.  We must continue using the original name, so                    // rename the new package here.                    pkg.setPackageName(oldName);                    pkgName = pkg.packageName;                    replace = true;                    if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="                            + oldName + " pkgName=" + pkgName);                } else if (mPackages.containsKey(pkgName)) {                    // This package, under its official name, already exists                    // on the device; we should replace it.                    replace = true;                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);                }                // Prevent apps opting out from runtime permissions                if (replace) {                    PackageParser.Package oldPackage = mPackages.get(pkgName);                    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;                    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1                            && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {                        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,                                "Package " + pkg.packageName + " new target SDK " + newTargetSdk                                        + " doesn't support runtime permissions but the old"                                        + " target SDK " + oldTargetSdk + " does.");                        return;                    }                }            }            PackageSetting ps = mSettings.mPackages.get(pkgName);            if (ps != null) {                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);                // Quick sanity check that we're signed correctly if updating;                // we'll check this again later when scanning, but we want to                // bail early here before tripping over redefined permissions.                if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {                    if (!checkUpgradeKeySetLP(ps, pkg)) {                        res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "                                + pkg.packageName + " upgrade keys do not match the "                                + "previously installed version");                        return;                    }                } else {                    try {                        verifySignaturesLP(ps, pkg);                    } catch (PackageManagerException e) {                        res.setError(e.error, e.getMessage());                        return;                    }                }                oldCodePath = mSettings.mPackages.get(pkgName).codePathString;                if (ps.pkg != null && ps.pkg.applicationInfo != null) {                    systemApp = (ps.pkg.applicationInfo.flags &                            ApplicationInfo.FLAG_SYSTEM) != 0;                }                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);            }            // Check whether the newly-scanned package wants to define an already-defined perm            int N = pkg.permissions.size();            for (int i = N-1; i >= 0; i--) {                PackageParser.Permission perm = pkg.permissions.get(i);                BasePermission bp = mSettings.mPermissions.get(perm.info.name);                if (bp != null) {                    // If the defining package is signed with our cert, it's okay.  This                    // also includes the "updating the same package" case, of course.                    // "updating same package" could also involve key-rotation.                    final boolean sigsOk;                    if (bp.sourcePackage.equals(pkg.packageName)                            && (bp.packageSetting instanceof PackageSetting)                            && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,                                    scanFlags))) {                        sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);                    } else {                        sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,                                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;                    }                    if (!sigsOk) {                        // If the owning package is the system itself, we log but allow                        // install to proceed; we fail the install on all other permission                        // redefinitions.                        if (!bp.sourcePackage.equals("android")) {                            res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "                                    + pkg.packageName + " attempting to redeclare permission "                                    + perm.info.name + " already owned by " + bp.sourcePackage);                            res.origPermission = perm.info.name;                            res.origPackage = bp.sourcePackage;                            return;                        } else {                            Slog.w(TAG, "Package " + pkg.packageName                                    + " attempting to redeclare system permission "                                    + perm.info.name + "; ignoring new declaration");                            pkg.permissions.remove(i);                        }                    }                }            }        }        if (systemApp && onExternal) {            // Disable updates to system apps on sdcard            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,                    "Cannot install updates to system apps on sdcard");            return;        }        if (args.move != null) {            // We did an in-place move, so dex is ready to roll            scanFlags |= SCAN_NO_DEX;            scanFlags |= SCAN_MOVE;            synchronized (mPackages) {                final PackageSetting ps = mSettings.mPackages.get(pkgName);                if (ps == null) {                    res.setError(INSTALL_FAILED_INTERNAL_ERROR,                            "Missing settings for moved package " + pkgName);                }                // We moved the entire application as-is, so bring over the                // previously derived ABI information.                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;            }        } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {            // Enable SCAN_NO_DEX flag to skip dexopt at a later stage            scanFlags |= SCAN_NO_DEX;            try {                derivePackageAbi(pkg, new File(pkg.codePath), args.abiOverride,                        true /* extract libs */);            } catch (PackageManagerException pme) {                Slog.e(TAG, "Error deriving application ABI", pme);                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");                return;            }            // Run dexopt before old package gets removed, to minimize time when app is unavailable            int result = mPackageDexOptimizer                    .performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,                            false /* defer */, false /* inclDependencies */,                            true /* boot complete */);            if (result == PackageDexOptimizer.DEX_OPT_FAILED) {                res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);                return;            }        }        if (!args.doRename(res.returnCode, pkg, oldCodePath)) {            res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");            return;        }        startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);        if (replace) {            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,                    installerPackageName, volumeUuid, res);        } else {            installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,                    args.user, installerPackageName, volumeUuid, res);        }        synchronized (mPackages) {            final PackageSetting ps = mSettings.mPackages.get(pkgName);            if (ps != null) {                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);            }        }    }

12.分析安装新应用的方法installNewPackageLI(),如下:

   12.1调用APK扫描函数scanPackageLI(),这个函数应该比较熟悉,主要做以下几件事情

          1.scanPakcageLI()pkg对象进行处理,主要完成以下几件事情

          2.Package分配UserId或所属的ShareUserId

          3.Installd发送命令,为非系统APK创建已PackageName命名的目录

          4.提取Native动态库,并获取CPUABI信息

          5.将四大组件的信息保存到PKMS的变量中,方便对外提供统一的组件信息。

    12.2调用updateSettingsLI()对安装进行后处理

         1.调用updatePermissionsLPw来为前面安装的应用程序分配Linux用户组ID,即授予它们所申请的资源访问权限。

          2.调用Settings类的成员函数writeLP将这些应用程序的安装信息保存在本地文件中

 private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,            UserHandle user, String installerPackageName, String volumeUuid,            PackageInstalledInfo res) {        // Remember this for later, in case we need to rollback this install        String pkgName = pkg.packageName;        if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);        final boolean dataDirExists = Environment                .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();        synchronized(mPackages) {            if (mSettings.mRenamedPackages.containsKey(pkgName)) {                // A package with the same name is already installed, though                // it has been renamed to an older name.  The package we                // are trying to install should be installed as an update to                // the existing one, but that has not been requested, so bail.                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName                        + " without first uninstalling package running as "                        + mSettings.mRenamedPackages.get(pkgName));                return;            }            if (mPackages.containsKey(pkgName)) {                // Don't allow installation over an existing package with the same name.                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName                        + " without first uninstalling.");                return;            }        }        try {            PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,                    System.currentTimeMillis(), user);            updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);            // delete the partially installed application. the data directory will have to be            // restored if it was already existing            if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {                // remove package from internal structures.  Note that we want deletePackageX to                // delete the package data and cache directories that it created in                // scanPackageLocked, unless those directories existed before we even tried to                // install.                deletePackageLI(pkgName, UserHandle.ALL, false, null, null,                        dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,                                res.removedInfo, true);            }        } catch (PackageManagerException e) {            res.setError("Package couldn't be installed in " + pkg.codePath, e);        }    }

12  以上步骤完成后,mHandler发送一个POST_INSTALL消息,POST_INSTALL消息的处理主要就是发送广播,应用安装完成后要通知系统中其他的应用开始处理。

case POST_INSTALL: {                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);                    PostInstallData data = mRunningInstalls.get(msg.arg1);                    mRunningInstalls.delete(msg.arg1);                    boolean deleteOld = false;                    if (data != null) {                        InstallArgs args = data.args;                        PackageInstalledInfo res = data.res;                        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {                            final String packageName = res.pkg.applicationInfo.packageName;                            res.removedInfo.sendBroadcast(false, true, false);                            Bundle extras = new Bundle(1);                            extras.putInt(Intent.EXTRA_UID, res.uid);                            // Now that we successfully installed the package, grant runtime                            // permissions if requested before broadcasting the install.                            if ((args.installFlags                                    & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {                                grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),                                        args.installGrantPermissions);                            }                            // Determine the set of users who are adding this                            // package for the first time vs. those who are seeing                            // an update.                            int[] firstUsers;                            int[] updateUsers = new int[0];                            if (res.origUsers == null || res.origUsers.length == 0) {                                firstUsers = res.newUsers;                            } else {                                firstUsers = new int[0];                                for (int i=0; i<res.newUsers.length; i++) {                                    int user = res.newUsers[i];                                    boolean isNew = true;                                    for (int j=0; j<res.origUsers.length; j++) {                                        if (res.origUsers[j] == user) {                                            isNew = false;                                            break;                                        }                                    }                                    if (isNew) {                                        int[] newFirst = new int[firstUsers.length+1];                                        System.arraycopy(firstUsers, 0, newFirst, 0,                                                firstUsers.length);                                        newFirst[firstUsers.length] = user;                                        firstUsers = newFirst;                                    } else {                                        int[] newUpdate = new int[updateUsers.length+1];                                        System.arraycopy(updateUsers, 0, newUpdate, 0,                                                updateUsers.length);                                        newUpdate[updateUsers.length] = user;                                        updateUsers = newUpdate;                                    }                                }                            }                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,                                    packageName, extras, null, null, firstUsers);                            final boolean update = res.removedInfo.removedPackage != null;                            if (update) {                                extras.putBoolean(Intent.EXTRA_REPLACING, true);                            }                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,                                    packageName, extras, null, null, updateUsers);                            if (update) {                                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,                                        packageName, extras, null, null, updateUsers);                                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,                                        null, null, packageName, null, updateUsers);                                // treat asec-hosted packages like removable media on upgrade                                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {                                    if (DEBUG_INSTALL) {                                        Slog.i(TAG, "upgrading pkg " + res.pkg                                                + " is ASEC-hosted -> AVAILABLE");                                    }                                    int[] uidArray = new int[] { res.pkg.applicationInfo.uid };                                    ArrayList<String> pkgList = new ArrayList<String>(1);                                    pkgList.add(packageName);                                    sendResourcesChangedBroadcast(true, true,                                            pkgList,uidArray, null);                                }                            }                            if (res.removedInfo.args != null) {                                // Remove the replaced package's older resources safely now                                deleteOld = true;                            }                            // If this app is a browser and it's newly-installed for some                            // users, clear any default-browser state in those users                            if (firstUsers.length > 0) {                                // 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, firstUsers[0])) {                                    synchronized (mPackages) {                                        for (int userId : firstUsers) {                                            mSettings.setDefaultBrowserPackageNameLPw(null, 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();                        // We delete after a gc for applications  on sdcard.                        if (deleteOld) {                            synchronized (mInstallLock) {                                res.removedInfo.args.doPostDeleteLI(true);                            }                        }                        if (args.observer != null) {                            try {                                Bundle extras = extrasForInstallResult(res);                                args.observer.onPackageInstalled(res.name, res.returnCode,                                        res.returnMsg, extras);                            } catch (RemoteException e) {                                Slog.i(TAG, "Observer no longer exists.");                            }                        }                    } else {                        Slog.e(TAG, "Bogus post-install token " + msg.arg1);                    }                } break;

至此,APK安装完成。














       







阅读全文
0 0
原创粉丝点击