Android Apk安装过程分析

Android Apk安装过程分析

本文以android 8.0(API Level:26) 源码讲解apk安装过程

APk安装主要步骤

  • copy apk到data/app目录下
  • 解析apk信息
  • 更新权限信息
  • 发送安装广播

一.将apk文件copy至data/app目录

安装过程是从调用ApplicationPackageManager.install()方法开始

1.1 ApplicationPackageManager.installCommon


#ApplicationPackageManager

protected ApplicationPackageManager(ContextImpl context,IPackageManager pm) {
        mContext = context;
        mPM = pm;
}

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

内部是调用mPm.installPackageAsUser方法,这里的Pm其实就是PackageManagerService对象

1.2. installPackageAsUser 发送INIT_COPY广播

#PackageManagerService



@Override
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, int userId) {
       final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId,
                true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");

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

        if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
                || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
            throw new IllegalArgumentException(
                    "New installs into ASEC containers no longer supported");
        }

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

      // 构建INIT_COPY的Message
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final VerificationInfo verificationInfo = new VerificationInfo(
                null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
        final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
                installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
                null /*packageAbiOverride*/, null /*grantedPermissions*/,
                null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);
        params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;

        

        mHandler.sendMessage(msg);

这里主要判断安装来源是属于adb、shell还是All_User,然后用mHandler发送INIT_COPY的消息

1.3 处理INIT_COPY和MCS_BOUND


#PackageHandler

class PackageHandler extends Handler {
        private boolean mBound = false;
        final ArrayList mPendingInstalls =
            new ArrayList();

       
        PackageHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            try {
                doHandleMessage(msg);
            } finally {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            }
        }


 void doHandleMessage(Message msg) {
            switch (msg.what) {
                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) {
                        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()) {
                            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 {
                            // 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;
                }
 }
 


  case MCS_BOUND: {
        if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
        if (msg.obj != null) {
            mContainerService = (IMediaContainerService) msg.obj;
            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();
            } else {
                Slog.w(TAG, "Waiting to connect to media container service");
            }
        } else if (mPendingInstalls.size() > 0) {
            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()) {
                    // 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);
                    }
                }
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        } else {
            // Should never happen ideally.
            Slog.w(TAG, "Empty queue");
        }
        break;
    }
    

在INIT_COPYz这个case中主要是确保DefaultContainerService已bound,DefaultContainerService是一个应用服务,具体负责实现APK等相关资源文件在内部或外部存储器上的存储工作, 然后发送MCS_BOUND的消息,在MCS_BOUND这个case中 最关键的代码就是
params.startCopy()

1.4 HandlerParams.startCopy()


# HandlerParams

private abstract class HandlerParams {
        private static final int MAX_RETRIES = 4;

               private int mRetries = 0;

        /** User handle for the user requesting the information or installation. */
        private final UserHandle mUser;
        String traceMethod;
        int traceCookie;

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

        final void serviceError() {
            if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
            handleServiceError();
            handleReturnCode();
        }

        abstract void handleStartCopy() throws RemoteException;
        abstract void handleServiceError();
        abstract void handleReturnCode();
    }


这里是直接调用 handleStartCopy()


 int ret = PackageManager.INSTALL_SUCCEEDED;
            ...
            ...
            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) {
                    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);
                    }
                }
            }
            ...
            ...
                     * No package verification is enabled, so immediately start
                     * the remote call to initiate copy using temporary file.
                     */
                    ret = args.copyApk(mContainerService, true);
               
            }
            mRet = ret;
        }


handleStartCopy的核心是InstallArgs的copyApk(),其他的都是些存储空间检查,权限检查等等安全校验, copyApk方法会把apk copy到data/app目录下

1.6 FileInstallArgs#copyApk


class FileInstallArgs extends InstallArgs {
    int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
        try {
            return doCopyApk(imcs, temp);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

}




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_INSTANT_APP) != 0;
        final File tempDir =
                mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
        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;
}


1.7 startCopy


final boolean startCopy() {
            boolean res;
            try {
              
                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;
        }

解析apk信息

在执行完拷贝apk的操作后,执行handleReturnCode(),该方法的作用是解析apk

2.1 handleReturnCode


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);
            }
        }
        
        
        
        
 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); //1.安装
                    }
                    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 {
                            bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token); //2.调用backup服务
                        } 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);
                }
            }
        });}

这里有几个关键步骤

1.installPackageLI(args, res); 解析Package和后续操作
2.bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);

我们先看installPackageLI(args, res)方法

2.2



private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
        final int installFlags = args.installFlags;
        String installerPackageName = args.installerPackageName;
        File tmpPackageFile = new File(args.getCodePath());
        boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
        boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
        boolean replace = false;
        final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
        // 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)
                | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setDisplayMetrics(mMetrics);

        final PackageParser.Package pkg;
        try {
        
        
            //解析包信息,将解析结果存放到PackageParser.Package中
            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;
                try {
            pp.collectCertificates(pkg, parseFlags);
            pp.collectManifestDigest(pkg);
        } catch (PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }

                pp = null;
        String oldCodePath = null;
        boolean systemApp = false;
        
        
        //校验自定义权限:APP含有一个或多个相同自定义权限,签名不一致无法正常安装
        
        synchronized (mPackages) {
            // 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)
                            || !bp.packageSetting.keySetData.isUsingUpgradeKeySets()
                            || ((PackageSetting) bp.packageSetting).sharedUser != null) {
                        sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
                                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
                    } else {
                        sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
                    }
                    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.
                        
                        //如果是非android系统app则直接拦截,系统应用的话则允许安装但是移除该权限
                        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);
                        }
                    }
                }
            }

            // 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);
                }
            }
            PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
                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);
            }
        }

       
        if (replace) {
            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                    installerPackageName, res);
        } else {
            installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, res);
        }
        synchronized (mPackages) {
            final PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            }
        }
    }

这个方法先是解析了package包,然后做了大量签名和权限校验的工作,最终会走到

2.2

if (replace) {
    replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
            installerPackageName, res);
} else {
    installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
            args.user, installerPackageName, res);
}

if (replace) {
    replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
            installerPackageName, res);
} else {
    installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
            args.user, installerPackageName, res);
}

根据是首次安装还是非首次安装,如果是首次安装,执行installNewPackageLI(),非首次安装,执行replacePackageLI(),

这里我们先看首次安装的情况

2.3 installNewPackageLI


 private void installNewPackageLI(PackageParser.Package pkg,
            int parseFlags, int scanFlags, UserHandle user,
            String installerPackageName, 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);
        boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).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, null, null, res);
            // 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);
        }
    }


这个方法主要做了两件事

  • scanPackageLI(pkg, parseFlags, scanFlags,
    System.currentTimeMillis(), user)
  • updateSettingsLI(newPackage, installerPackageName

scanPackageLI 负责安装,updateSettingsLI负责安装完成后的设置信息更新

2.4 scanPackageLI

scanPackageLI()中主要逻辑是scanPackageDirtyLI()实现的,这个方法中主要做的事情有

1.设置系统App的一些参数
2.校验签名
3.校验权限

在 scanPackageLI会调用到performDexOptLI(),去执行dexopt操作

2.5 updateSettingsLI 更新设置信息

private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
            int[] allUsers, PackageInstalledInfo res, UserHandle user, int installReason) {
        // Update the parent package setting
    updateSettingsInternalLI(newPackage, installerPackageName, allUsers, res.origUsers,
            res, user, installReason);
    // Update the child packages setting
    final int childCount = (newPackage.childPackages != null)
            ? newPackage.childPackages.size() : 0;
    for (int i = 0; i < childCount; i++) {
        PackageParser.Package childPackage = newPackage.childPackages.get(i);
        PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
        updateSettingsInternalLI(childPackage, installerPackageName, allUsers,
                childRes.origUsers, childRes, user, installReason);
    }
}


updateSettingsInternalLI()会调用到updatePermissionsLPw


 private void updateSettingsInternalLI(PackageParser.Package newPackage,
            String installerPackageName, int[] allUsers, int[] installedForUsers,
            PackageInstalledInfo res, UserHandle user, int installReason) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");

        ...
        ...
        installed in " + newPackage.codePath);
        synchronized (mPackages) {
            updatePermissionsLPw(newPackage.packageName, newPackage,
                    UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
                            ? UPDATE_PERMISSIONS_ALL : 0));
          
    }

updateSettingsInternalLI()会调用到updatePermissionsLPw

更新权限信息

3.1 updatePermissionsLPw

private void updatePermissionsLPw(PackageParser.Package pkg, int flags) {
        // Update the parent permissions
    updatePermissionsLPw(pkg.packageName, pkg, flags);
    // Update the child permissions
    final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
    for (int i = 0; i < childCount; i++) {
        PackageParser.Package childPkg = pkg.childPackages.get(i);
        updatePermissionsLPw(childPkg.packageName, childPkg, flags);
    }
}


private void updatePermissionsLPw(String changingPkg,
           PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
                      
  ...
  ...
   if (pkgInfo != null) {
       // Only replace for packages on requested volume
       final String volumeUuid = getVolumeUuidForPackage(pkgInfo);
       final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
               && Objects.equals(replaceVolumeUuid, volumeUuid);
       grantPermissionsLPw(pkgInfo, replace, changingPkg);
   }
   Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}


调用到grantPermissionsLPw


 private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
           String packageOfInterest) {
           
            final int N = pkg.requestedPermissions.size();
       for (int i=0; i= Build.VERSION_CODES.M;

           if (DEBUG_INSTALL) {
               Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
           }

           if (bp == null || bp.packageSetting == null) {
               if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
                   if (DEBUG_PERMISSIONS) {
                       Slog.i(TAG, "Unknown permission " + name
                               + " in package " + pkg.packageName);
                   }
               }
               continue;
           }


           // Limit ephemeral apps to ephemeral allowed permissions.
           if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
               if (DEBUG_PERMISSIONS) {
                   Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
                           + pkg.packageName);
               }
               continue;
           }

           if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
               if (DEBUG_PERMISSIONS) {
                   Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
                           + pkg.packageName);
               }
               continue;
           }

           final String perm = bp.name;
           boolean allowedSig = false;
           int grant = GRANT_DENIED;

           // Keep track of app op permissions.
           if ((bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
               ArraySet pkgs = mAppOpPermissionPackages.get(bp.name);
               if (pkgs == null) {
                   pkgs = new ArraySet<>();
                   mAppOpPermissionPackages.put(bp.name, pkgs);
               }
               pkgs.add(pkg.packageName);
           }

           final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
           switch (level) {
               case PermissionInfo.PROTECTION_NORMAL: {
                   // For all apps normal permissions are install time ones.
                   grant = GRANT_INSTALL;
               } break;

               case PermissionInfo.PROTECTION_DANGEROUS: {
                   // If a permission review is required for legacy apps we represent
                   // their permissions as always granted runtime ones since we need
                   // to keep the review required permission flag per user while an
                   // install permission's state is shared across all users.
                   if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
                       // For legacy apps dangerous permissions are install time ones.
                       grant = GRANT_INSTALL;
                   } else if (origPermissions.hasInstallPermission(bp.name)) {
                       // For legacy apps that became modern, install becomes runtime.
                       grant = GRANT_UPGRADE;
                   } else if (mPromoteSystemApps
                           && isSystemApp(ps)
                           && mExistingSystemPackages.contains(ps.name)) {
                       // For legacy system apps, install becomes runtime.
                       // We cannot check hasInstallPermission() for system apps since those
                       // permissions were granted implicitly and not persisted pre-M.
                       grant = GRANT_UPGRADE;
                   } else {
                       // For modern apps keep runtime permissions unchanged.
                       grant = GRANT_RUNTIME;
                   }
               } break;

               case PermissionInfo.PROTECTION_SIGNATURE: {
                   // For all apps signature permissions are install time ones.
                   allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
                   if (allowedSig) {
                       grant = GRANT_INSTALL;
                   }
               } break;
           }

           if (DEBUG_PERMISSIONS) {
               Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName);
           }

           if (grant != GRANT_DENIED) {
               if (!isSystemApp(ps) && ps.installPermissionsFixed) {
                   // If this is an existing, non-system package, then
                   // we can't add any new permissions to it.
                   if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
                       // Except...  if this is a permission that was added
                       // to the platform (note: need to only do this when
                       // updating the platform).
                       if (!isNewPlatformPermissionForPackage(perm, pkg)) {
                           grant = GRANT_DENIED;
                       }
                   }
               }

               switch (grant) {
                   case GRANT_INSTALL: {
                       // Revoke this as runtime permission to handle the case of
                       // a runtime permission being downgraded to an install one.
                       // Also in permission review mode we keep dangerous permissions
                       // for legacy apps
                       for (int userId : UserManagerService.getInstance().getUserIds()) {
                           if (origPermissions.getRuntimePermissionState(
                                   bp.name, userId) != null) {
                               // Revoke the runtime permission and clear the flags.
                               origPermissions.revokeRuntimePermission(bp, userId);
                               origPermissions.updatePermissionFlags(bp, userId,
                                     PackageManager.MASK_PERMISSION_FLAGS, 0);
                               // If we revoked a permission permission, we have to write.
                               changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                       changedRuntimePermissionUserIds, userId);
                           }
                       }
                       // Grant an install permission.
                       if (permissionsState.grantInstallPermission(bp) !=
                               PermissionsState.PERMISSION_OPERATION_FAILURE) {
                           changedInstallPermission = true;
                       }
                   } break;

                   case GRANT_RUNTIME: {
                       // Grant previously granted runtime permissions.
                       for (int userId : UserManagerService.getInstance().getUserIds()) {
                           PermissionState permissionState = origPermissions
                                   .getRuntimePermissionState(bp.name, userId);
                           int flags = permissionState != null
                                   ? permissionState.getFlags() : 0;
                           if (origPermissions.hasRuntimePermission(bp.name, userId)) {
                               // Don't propagate the permission in a permission review mode if
                               // the former was revoked, i.e. marked to not propagate on upgrade.
                               // Note that in a permission review mode install permissions are
                               // represented as constantly granted runtime ones since we need to
                               // keep a per user state associated with the permission. Also the
                               // revoke on upgrade flag is no longer applicable and is reset.
                               final boolean revokeOnUpgrade = (flags & PackageManager
                                       .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
                               if (revokeOnUpgrade) {
                                   flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
                                   // Since we changed the flags, we have to write.
                                   changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                           changedRuntimePermissionUserIds, userId);
                               }
                               if (!mPermissionReviewRequired || !revokeOnUpgrade) {
                                   if (permissionsState.grantRuntimePermission(bp, userId) ==
                                           PermissionsState.PERMISSION_OPERATION_FAILURE) {
                                       // If we cannot put the permission as it was,
                                       // we have to write.
                                       changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                               changedRuntimePermissionUserIds, userId);
                                   }
                               }

                               // If the app supports runtime permissions no need for a review.
                               if (mPermissionReviewRequired
                                       && appSupportsRuntimePermissions
                                       && (flags & PackageManager
                                               .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
                                   flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
                                   // Since we changed the flags, we have to write.
                                   changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                           changedRuntimePermissionUserIds, userId);
                               }
                           } else if (mPermissionReviewRequired
                                   && !appSupportsRuntimePermissions) {
                               // For legacy apps that need a permission review, every new
                               // runtime permission is granted but it is pending a review.
                               // We also need to review only platform defined runtime
                               // permissions as these are the only ones the platform knows
                               // how to disable the API to simulate revocation as legacy
                               // apps don't expect to run with revoked permissions.
                               if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) {
                                   if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
                                       flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                       // We changed the flags, hence have to write.
                                       changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                               changedRuntimePermissionUserIds, userId);
                                   }
                               }
                               if (permissionsState.grantRuntimePermission(bp, userId)
                                       != PermissionsState.PERMISSION_OPERATION_FAILURE) {
                                   // We changed the permission, hence have to write.
                                   changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                           changedRuntimePermissionUserIds, userId);
                               }
                           }
                           // Propagate the permission flags.
                           permissionsState.updatePermissionFlags(bp, userId, flags, flags);
                       }
                   } break;

                   case GRANT_UPGRADE: {
                       // Grant runtime permissions for a previously held install permission.
                       PermissionState permissionState = origPermissions
                               .getInstallPermissionState(bp.name);
                       final int flags = permissionState != null ? permissionState.getFlags() : 0;

                       if (origPermissions.revokeInstallPermission(bp)
                               != PermissionsState.PERMISSION_OPERATION_FAILURE) {
                           // We will be transferring the permission flags, so clear them.
                           origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
                                   PackageManager.MASK_PERMISSION_FLAGS, 0);
                           changedInstallPermission = true;
                       }

                       // If the permission is not to be promoted to runtime we ignore it and
                       // also its other flags as they are not applicable to install permissions.
                       if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
                           for (int userId : currentUserIds) {
                               if (permissionsState.grantRuntimePermission(bp, userId) !=
                                       PermissionsState.PERMISSION_OPERATION_FAILURE) {
                                   // Transfer the permission flags.
                                   permissionsState.updatePermissionFlags(bp, userId,
                                           flags, flags);
                                   // If we granted the permission, we have to write.
                                   changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                           changedRuntimePermissionUserIds, userId);
                               }
                           }
                       }
                   } break;

                   default: {
                       if (packageOfInterest == null
                               || packageOfInterest.equals(pkg.packageName)) {
                           if (DEBUG_PERMISSIONS) {
                               Slog.i(TAG, "Not granting permission " + perm
                                       + " to package " + pkg.packageName
                                       + " because it was previously installed without");
                           }
                       }
                   } break;
               }
           } else {
               if (permissionsState.revokeInstallPermission(bp) !=
                       PermissionsState.PERMISSION_OPERATION_FAILURE) {
                   // Also drop the permission flags.
                   permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
                           PackageManager.MASK_PERMISSION_FLAGS, 0);
                   changedInstallPermission = true;
                   Slog.i(TAG, "Un-granting permission " + perm
                           + " from package " + pkg.packageName
                           + " (protectionLevel=" + bp.protectionLevel
                           + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
                           + ")");
               } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
                   // Don't print warning for app op permissions, since it is fine for them
                   // not to be granted, there is a UI for the user to decide.
                   if (DEBUG_PERMISSIONS
                           && (packageOfInterest == null
                                   || packageOfInterest.equals(pkg.packageName))) {
                       Slog.i(TAG, "Not granting permission " + perm
                               + " to package " + pkg.packageName
                               + " (protectionLevel=" + bp.protectionLevel
                               + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
                               + ")");
                   }
               }
           }
       }

       if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
               !isSystemApp(ps) || isUpdatedSystemApp(ps)){
           // This is the first that we have heard about this package, so the
           // permissions we have now selected are fixed until explicitly
           // changed.
           ps.installPermissionsFixed = true;
       }

       // Persist the runtime permissions state for users with changes. If permissions
       // were revoked because no app in the shared user declares them we have to
       // write synchronously to avoid losing runtime permissions state.
       for (int userId : changedRuntimePermissionUserIds) {
           mSettings.writeRuntimePermissionsForUserLPr(userId, runtimePermissionsRevoked);
       }
           
} 

这个方法的作用是将该app的所有权限都记录下来

四.发送安装完成广播

前面processPendingInstall方法中,在执行完installPackageLi后,会执行 bm.restoreAtInstall()方法,实际调用的是BackupManagerService的restoreAtInstall()方法

#BackupManagerService

@Override
    public void restoreAtInstall(String packageName, int token) {
    ...
    ...
              
    if (skip) {
        // Auto-restore disabled or no way to attempt a restore

        if (transportClient != null) {
            mTransportManager.disposeOfTransportClient(
                    transportClient, "BMS.restoreAtInstall()");
        }

        // Tell the PackageManager to proceed with the post-install handling for this package.
        if (DEBUG) Slog.v(TAG, "Finishing install immediately");
        try {
            mPackageManagerBinder.finishPackageInstall(token, false);
        } catch (RemoteException e) { /* can't happen */ }
    }
}


这里会调用到 mPackageManagerBinder.finishPackageInstall(token, false)方法, 也就是PackageManagerService的finishPackageInstall()方法


#PacakageManagerService

@Override
    public void finishPackageInstall(int token, boolean didLaunch) {
        enforceSystemOrRoot("Only the system is allowed to finish installs");

           
        final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
        mHandler.sendMessage(msg);
    }

在PacakageManagerService的finishPackageInstall会发送POST_INSTALL的广播


# PacakageManagerService
  case POST_INSTALL: {
       
            // Handle the parent package
            handlePackagePostInstall(parentRes, grantPermissions, killApp,
                    virtualPreload, 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,
                        virtualPreload, grantedPermissions, false /*didRestore*/,
                        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);
        }

        
    } break;



private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, boolean virtualPreload, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {
    


     if (update) {
        extras.putBoolean(Intent.EXTRA_REPLACING, true);
    }
    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
            extras, 0 /*flags*/,
            null /*targetPackage*/, null /*finishedReceiver*/,
            updateUserIds, instantUserIds);
    if (installerPackageName != null) {
        sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                extras, 0 /*flags*/,
                installerPackageName, null /*finishedReceiver*/,
                updateUserIds, instantUserIds);
    }
    
    
   if (update) {
        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                packageName, extras, 0 /*flags*/,
                null /*targetPackage*/, null /*finishedReceiver*/,
                updateUserIds, instantUserIds);
        if (installerPackageName != null) {
            sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                    extras, 0 /*flags*/,
                    installerPackageName, null /*finishedReceiver*/,
                    updateUserIds, instantUserIds);
        }
        if (notifyVerifier) {
            sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                    extras, 0 /*flags*/,
                    mRequiredVerifierPackage, null /*finishedReceiver*/,
                    updateUserIds, instantUserIds);
        }
        sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                null /*package*/, null /*extras*/, 0 /*flags*/,
                packageName /*targetPackage*/,
                null /*finishedReceiver*/, updateUserIds, instantUserIds);
    } 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(firstUserIds));
        }
        sendFirstLaunchBroadcast(packageName, installerPackage,
                firstUserIds, firstInstantUserIds);
    }

}

发送Intent.ACTION_PACKAGE_ADDED或者Intent.ACTION_PACKAGE_REPLACED的广播,至此,app的安装流程就结束了

你可能感兴趣的:(Android Apk安装过程分析)