栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android PMS (1/3)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android PMS (1/3)

简介

该系列,我们将学习PMS如何处理apk的安装

一、PackageHandler处理安装消息

APK的信息交由PMS后,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。先来查看PackageHandler处理安装消息的调用时序图。

1.1 PMS的installStage方法 

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

void installStage(String packageName, File stagedDir,
        IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
        String installerPackageName, int installerUid, UserHandle user,
        PackageParser.SigningDetails signingDetails) {
    ...
    final VerificationInfo verificationInfo = new VerificationInfo(
            sessionParams.originatingUri, sessionParams.referrerUri,
            sessionParams.originatingUid, installerUid);

    final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);

    final Message msg = mHandler.obtainMessage(INIT_COPY);
    final int installReason = fixUpInstallReason(installerPackageName, installerUid,
            sessionParams.installReason);
    //创建InstallParams,它对应于包的安装数据
    final InstallParams params = new InstallParams(origin, null, observer,
            sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
            verificationInfo, user, sessionParams.abiOverride,
            sessionParams.grantedRuntimePermissions, signingDetails, installReason);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;
    ...
    mHandler.sendMessage(msg);
}

PackageManagerService.java#InstallParams

class InstallParams extends HandlerParams {
    final OriginInfo origin;
    final MoveInfo move;
    final IPackageInstallObserver2 observer;
    int installFlags;
    final String installerPackageName;
    final String volumeUuid;
    private InstallArgs mArgs;
    private int mRet;
    final String packageAbiOverride;
    final String[] grantedRuntimePermissions;
    final VerificationInfo verificationInfo;
    final PackageParser.SigningDetails signingDetails;
    final int installReason;
    ...
}
1.2 对INIT_COPY的消息的处理

PackageManagerService.java#PackageHandler

public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
        DEFAULT_CONTAINER_PACKAGE,
        "com.android.defcontainer.DefaultContainerService");

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

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

class PackageHandler extends Handler {
    private boolean mBound = false;
    final ArrayList mPendingInstalls =
        new ArrayList();
    ...
    private boolean connectToService() {
        if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService");
        Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
        Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
        if (mContext.bindServiceAsUser(service, mDefContainerConn,
                Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            mBound = true;
            return true;
        }
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        return false;
    }

    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 a bind was already initiated we dont really
                // need to do anything. The pending install
                // will be processed later on.
                //mBound用于标识是否绑定了服务,默认值为false
                if (!mBound) {
                    // If this is the only one pending we might
                    // have to bind to the service again.
                    //如果没有绑定服务,重新绑定,connectToService方法内部如果绑定成功会将mBound置为true
                    if (!connectToService()) {
                        params.serviceError();
                        //绑定服务失败则return
                        return;
                    } else {
                        // Once we bind to the service, the first
                        // pending request will be processed.
                        //绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
                        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) {
                        //注释2
                        mHandler.sendEmptyMessage(MCS_BOUND);
                    }
                }
                break;
            }
        }
    }
}

PackageHandler继承自Handler,它定义在PMS中,doHandleMessage方法用于处理各个类型的消息,mBound用于标识是否绑定了DefaultContainerService,默认值为false。DefaultContainerService是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此DefaultContainerService没有和PMS运行在同一进程中,它运行在com.android.defcontainer进程,通过IMediaContainerService和PMS进行IPC通信,如下图所示。

注释1处发送了MCS_BOUND类型的消息,与PackageHandler.doHandleMessage方法的注释2处不同的是,这里发送消息带了Object类型的参数,这里会对这两种情况来进行讲解,一种是消息不带Object类型的参数,一种是消息带Object类型的参数。

1.3 对MCS_BOUND类型的消息的处理

1.3.1 消息不带Object类型的参数
class PackageHandler extends Handler {
    ...
    void doHandleMessage(Message msg) {
        switch (msg.what) {
            ...
            case MCS_BOUND: {
                if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                if (msg.obj != null) {
                    mContainerService = (IMediaContainerService) msg.obj;
                    ...
                }
                //消息不带Object类型的参数进入该分支
                if (mContainerService == null) {
                    //注释1
                    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) {
                    ...
                } else {
                    // Should never happen ideally.
                    Slog.w(TAG, "Empty queue");
                }
                break;
            }
        }
    }
}

如果满足注释1处的条件,说明还没有绑定服务,而此前已经在PackageHandler.doHandleMessage方法的INIT_COPY处调用绑定服务的方法了,这显然是不正常的,因此处理服务发生错误的情况。如果不满足注释1处的条件,说明已经绑定服务了,就会打印出系统log,告知用户等待系统绑定服务。

1.3.2 消息带Object类型的参数
class PackageHandler extends Handler {
    ...
    void doHandleMessage(Message msg) {
        switch (msg.what) {
            ...
            case MCS_BOUND: {
                if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                if (msg.obj != null) {
                    mContainerService = (IMediaContainerService) msg.obj;
                    ...
                }
                if (mContainerService == null) {
                    ...
                } else if (mPendingInstalls.size() > 0) { //消息带Object类型的参数进入该分支
                    //得到安装请求队列第一个请求HandlerParams 
                    HandlerParams params = mPendingInstalls.get(0);
                    if (params != null) {
                        //调用HandlerParams的startCopy方法,用于开始复制APK的流程
                        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
                            //如果APK安装成功,删除本次安装请求
                            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");
                                //如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求   
                                mHandler.sendEmptyMessage(MCS_BOUND);
                            }
                        }
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                } else {
                    // Should never happen ideally.
                    Slog.w(TAG, "Empty queue");
                }
                break;
            }
        }
    }
}
二、复制apk

复制APK的时序图

 HandlerParams是PMS中的抽象类,它的实现类为PMS的内部类InstallParams。

PackageManagerService.java#HandlerParams

private abstract class HandlerParams {
    //startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
    private static final int MAX_RETRIES = 4;

    
    private int mRetries = 0;

    
    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;
        }
        //处理复制APK后的安装APK逻辑
        handleReturnCode();
        return res;
    }
    ...
    abstract void handleStartCopy() throws RemoteException;
    abstract void handleServiceError();
    abstract void handleReturnCode();
}

PackageManagerService.java#InstallParams

public void handleStartCopy() throws RemoteException {
    int ret = PackageManager.INSTALL_SUCCEEDED;
    ...
    //确定APK的安装位置 onSd:安装到SD卡 onInt:内部存储即Data分区 ephemeral:安装到临时存储(Instant Apps安装)
    final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
    final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
    final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
    PackageInfoLite pkgLite = null;

    if (onInt && onSd) {
        // APK不能同时安装在SD卡和Data分区
        // Check if both bits are set.
        Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    } else if (onSd && ephemeral) {
        //安装标志冲突,Instant Apps不能安装到SD卡中
        Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    } else {
        //注释1 获取APK的少量的信息
        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                packageAbiOverride);

        
        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, packageAbiOverride);

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

            
            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.
            //注释2
            loc = installLocationPolicy(pkgLite);
            if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
            } else if (!onSd && !onInt) {
                // Override install location with flags
                if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                    // Set the flag to install on external media.
                    installFlags |= PackageManager.INSTALL_EXTERNAL;
                    installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
                    if (DEBUG_INSTANT) {
                        Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                    }
                    installFlags |= PackageManager.INSTALL_INSTANT_APP;
                    installFlags &= ~(PackageManager.INSTALL_EXTERNAL
                            |PackageManager.INSTALL_INTERNAL);
                } else {
                    // Make sure the flag for installing on external
                    // media is unset
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                    installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                }
            }
        }
    }
    //注释3 根据InstallParams创建InstallArgs对象
    final InstallArgs args = createInstallArgs(this);
    mArgs = args;

    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        // TODO: http://b/22976637
        // Apps installed for "all" users use the device owner to verify the app
        UserHandle verifierUser = getUser();
        if (verifierUser == UserHandle.ALL) {
            verifierUser = UserHandle.SYSTEM;
        }

        
        final int requiredUid = mRequiredVerifierPackage == null ? -1
                : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
                        verifierUser.getIdentifier());
        final int installerUid =
                verificationInfo == null ? -1 : verificationInfo.installerUid;
        if (!origin.existing && requiredUid != -1
                && isVerificationEnabled(
                        verifierUser.getIdentifier(), installFlags, installerUid)) {
            ...
        } else {
            
            //注释4
            ret = args.copyApk(mContainerService, true);
        }
    }

    mRet = ret;
}

InstallParamshandleStartCopy方法的代码很多,这里截取关键的部分:
(1) 注释1处通过IMediaContainerService跨进程调用DefaultContainerService的getMinimalPackageInfo方法,该方法轻量解析APK并得到APK的少量信息,轻量解析的原因是这里不需要得到APK的全部信息,APK的少量信息会封装到PackageInfoLite中

(2) 注释2处确定APK的安装位置。

(3) 注释3处创建了InstallArgs,InstallArgs 是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,它有3个子类,都被定义在PMS中,如下图所示。

其中FileInstallArgs用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区),AsecInstallArgs用于处理安装到ASEC中(mnt/asec)即SD卡中的APK。MoveInstallArgs用于处理已安装APK的移动的逻辑。对APK进行检查后就会在注释4处调用InstallArgs的copyApk方法进行安装。不同的InstallArgs子类会有着不同的处理,这里以FileInstallArgs为例。FileInstallArgs的copyApk方法中会直接return FileInstallArgs的doCopyApk方法。

PackageManagerService.java#FileInstallArgs

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;
        //注释1 创建临时文件存储目录
        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;
    //注释2
    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处用于创建临时存储目录,比如/data/app/vmdl18300388.tmp,其中18300388是安装的sessionId。注释2处通过IMediaContainerService跨进程调用DefaultContainerService的copyPackage方法,这个方法会在DefaultContainerService所在的进程中将APK复制到临时存储目录,比如/data/app/vmdl18300388.tmp/base.apk。目前为止APK的复制工作就完成了,接着就是APK的安装过程了。

三、安装apk

 我们回到APK的复制调用链的头部方法:HandlerParams的startCopy方法会调用handleReturnCode方法,它的实现在InstallParams中,如下所示:

PackageManagerService.java#InstallParams

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

PackageManagerService.java

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    // Queue up an async operation since the package installation may take a little while.
    mHandler.post(new Runnable() {
        public void run() {
            mHandler.removeCallbacks(this);
             // Result object to be returned
            PackageInstalledInfo res = new PackageInstalledInfo();
            res.setReturnCode(currentStatus);
            res.uid = -1;
            res.pkg = null;
            res.removedInfo = null;
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                //注释1 安装前处理
                args.doPreInstall(res.returnCode);
                synchronized (mInstallLock) {
                    //注释2
                    installPackageTracedLI(args, res);
                }
                //注释3 安装后收尾
                args.doPostInstall(res.returnCode, res.uid);
            }
            ...
        }
    });
}
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
        installPackageLI(args, res);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}


private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    ...
    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);

    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        //注释1 解析APK
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        DexMetadataHelper.validatePackageDexMetadata(pkg);
    } catch (PackageParserException e) {
        res.setError("Failed parse during installPackageLI", e);
        return;
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    ...
    // 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
        // 检查APK是否存在
        if ((installFlags & PackageManager.INSTALL_REPLACe_EXISTING) != 0) {
            //获取没被改名前的包名
            String oldName = mSettings.getRenamedPackageLPr(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.
                //注释2
                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);
        //注释3 查看Settings中是否存有要安装的APK的信息,如果有就获取签名信息
        if (ps != null) {
            if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

            // Static shared libs have same package with different versions where
            // we internally use a synthetic package name to allow multiple versions
            // of the same package, therefore we need to compare signatures against
            // the package setting for the latest library version.
            PackageSetting signatureCheckPs = ps;
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
                if (libraryEntry != null) {
                    signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
                }
            }

            // 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.
            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
            //检查签名的正确性
            if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                            + pkg.packageName + " upgrade keys do not match the "
                            + "previously installed version");
                    return;
                }
            } else {
                ...
            }
            ...
        }

        int N = pkg.permissions.size();
        for (int i = N-1; i >= 0; i--) {
            //遍历每个权限,对权限进行处理
            final PackageParser.Permission perm = pkg.permissions.get(i);
            final BasePermission bp =
                    (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
            ...
        }
    }

    if (systemApp) {
        if (onExternal) {
            //系统APP不能在SD卡上替换安装
            // Abort update; system app can't be replaced with app on sdcard
            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
            return;
        } else if (instantApp) {
            //系统APP不能被Instant App替换
            // Abort update; system app can't be replaced with an instant app
            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Cannot update a system app with an instant app");
            return;
        }
    }

    ...
    //注释4 重命名临时文件
    if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
        res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
        return;
    }
    ...
    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
            "installPackageLI")) {
        if (replace) {
            //注释5 替换安装
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                // Static libs have a synthetic package name containing the version
                // and cannot be updated as an update would get a new package name,
                // unless this is the exact same version code which is useful for
                // development.
                PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
                if (existingPkg != null &&
                        existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
                    res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
                            + "static-shared libs cannot be updated");
                    return;
                }
            }
            replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
                    installerPackageName, res, args.installReason);
        } else {
            //安装新的APK
            installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, volumeUuid, res, args.installReason);
        }
    }
    ...
    synchronized (mPackages) {
        final PackageSetting ps = mSettings.mPackages.get(pkgName);
        if (ps != null) {
            //更新应用程序所属的用户
            res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            ps.setUpdateAvailable(false );
        }
        ...
    }
}

installPackageLI方法的代码有将近500行,这里截取主要的部分,主要做了几件事:

(1) 创建PackageParser解析APK
(2) 检查APK是否存在,如果存在就获取此前没被改名前的包名并在注释2处赋值给PackageParser.Package类型的pkg,在注释3处将标志位replace置为true表示是替换安装
(3) 注释3处,如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换
(4) 在注释4处将临时文件重新命名,比如前面提到的/data/app/vmdl18300388.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加。系统APP的更新安装会有两个限制,一个是系统APP不能在SD卡上替换安装,另一个是系统APP不能被Instant App替换
(5) 注释5处根据replace来做区分,如果是替换安装就会调用replacePackageLIF方法,其方法内部还会对系统APP和非系统APP进行区分处理,如果是新安装APK会调用installNewPackageLIF方法。
这里我们以新安装APK为例,会调用PMS的installNewPackageLIF方法。

private void installNewPackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags,
        final @ScanFlags int scanFlags, UserHandle user, String installerPackageName,
        String volumeUuid, PackageInstalledInfo res, int installReason) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");

    // Remember this for later, in case we need to rollback this install
    String pkgName = pkg.packageName;

    if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);

    synchronized(mPackages) {
        final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
        if (renamedPackage != null) {
            // 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 "
                    + renamedPackage);
            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 {
        //扫描APK
        PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
                System.currentTimeMillis(), user);
        //更新Settings信息
        updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            //安装成功后,为新安装的应用程序准备数据
            prepareAppDataAfterInstallLIF(newPackage);

        } else {
            // Remove package from internal structures, but keep around any
            // data that might have already existed
            //安装失败则删除APK
            deletePackageLIF(pkgName, UserHandle.ALL, false, null,
                    PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
        }
    } catch (PackageManagerException e) {
        res.setError("Package couldn't be installed in " + pkg.codePath, e);
    }

    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

installNewPackageLIF主要做了以下3件事:

(1) 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
(2) 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
(3) 如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/870629.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号