目录见上↑↑↑整个安装过程可分为三步:

    1.权限检查

    2.复制文件

    3.装载应用


1.权限检查

调用installPackageAsUser函数

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();// 利用binder机制,获取安装发起进程的uid//检查权限 该函数主要是检查进程是否有权限安装 展开见1.1enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");//检查当前用户是否具备安装app的权限if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {try {if (observer != null) {observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);}} catch (RemoteException re) {}        return;    }//如果是发起端进程是shell或者root,那么添加flags:PackageManager.INSTALL_FROM_ADB    if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {        installFlags |= PackageManager.INSTALL_FROM_ADB;    } else {        // 从flags中去掉INSTALL_FROM_ADB和INSTALL_ALL_USERS        installFlags &= ~PackageManager.INSTALL_FROM_ADB;        installFlags &= ~PackageManager.INSTALL_ALL_USERS;    }    UserHandle user;//创建一个当前用户的handle    if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {        user = UserHandle.ALL;    } else {        user = new UserHandle(userId);    }    // Only system components can circumvent runtime permissions when installing.// Android 6.0 当权限属于运行时权限时,需要弹出框,让用户授权,对于system app,应该取消运行时权限弹框授权,而是直接授权。// 那么就要在system app中加入INSTALL_GRANT_RUNTIME_PERMISSIONS;安装第三方app,当然没有INSTALL_GRANT_RUNTIME_PERMISSIONS了    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);//后续判断APK安装到哪里时,会用到//构造InstallParams,注意packageAbiOverride为null,然后利用Android中的Handler机制,发送给相关的线程进行安装。    final Message msg = mHandler.obtainMessage(INIT_COPY);    msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,            null, verificationParams, user, packageAbiOverride, null);    mHandler.sendMessage(msg);}
其主要流程如图所示:



1.1 enforceCrossUserPermission

installPackageAsUser方法的前部调用了enforceCrossUserPermission,代码如下:

void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission,            boolean checkShell, String message) {if (userId < 0) {throw new IllegalArgumentException("Invalid userId " + userId);    }    //当前userid和发起者进程所属的userid一致,那么OK,直接返回    // 我们现在就属于这种情况    if (userId == UserHandle.getUserId(callingUid)) return;    //不一致,那就要看是不是SYSTEM进程了,依旧不是,那么执行下逻辑,抛异常    if (callingUid != Process.SYSTEM_UID && callingUid != 0) {        if (requireFullPermission) {            mContext.enforceCallingOrSelfPermission(                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);        } else {            try {                mContext.enforceCallingOrSelfPermission(                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);            } catch (SecurityException se) {                mContext.enforceCallingOrSelfPermission(                        android.Manifest.permission.INTERACT_ACROSS_USERS, message);            }        }    }}


2.复制文件

权限检查中installPackageAsUser方法尾部会发送一个INIT_COPY消息,接着会使用doHandleMessage方法处理收到的消息:

2.1 INIT_COPY

void doHandleMessage(Message msg) {switch (msg.what) {case INIT_COPY: {HandlerParams params = (HandlerParams) msg.obj;//取出InstallParams            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.                // 将绑定DefaultContainerService服务                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中,等待收到连接的返回消息后,再继续安装                    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) {                    //如果mPendingInstalls中只有一项,那么立即发送MCS_BOUND消息                    mHandler.sendEmptyMessage(MCS_BOUND);                }            }            break;        }        ...        case 巴拉巴拉}}

INIT_COPY消息的处理中将绑定DefaultContainerService 因为这是一个异步的过程,要等待的绑定的结果通过onServiceConnected()返回,所以这里就将安装的参数信息放到了mPendingInstalls列表中。

如果这个Service之前就绑定好了,现在就不要再次绑定了,安装信息同样要放到mPendingInstalls中。

如果有多个安装请求同时到达,就可以通过mPendingInstalls列表对它们进行排队。

如果列表中只有一项,说明没有更多的安装请求,因此这种情况下,需要立即发出MCS_BOUND消息,进入下一步的处理。(应该有个INIT_COPY的流程图 简书那个)

2.1.1 connectToService

private boolean connectToService() {if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" + " DefaultContainerService");    Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);    if (mContext.bindServiceAsUser(service, mDefContainerConn,            Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        mBound = true;        return true;    }    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);    return false;}
绑定成功后在onServiceConnected中将一个IBinder转换成了一个IMediaContainerService。这个就是在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建的一个远程代理对象。以后PMS务通过该代理对象访问DefaultContainerService服务。

2.2 MCS_BOUND

case MCS_BOUND:  {if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");if (msg.obj != null) {mContainerService = (IMediaContainerService) msg.obj;}if (mContainerService == null) {//如果刚才绑定的DefaultContainerService失败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()) {//==============执行拷贝操作2.3        // 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.                // 如果没有安装信息了,则发送延时10秒的MCS_UNBIND消息                sendMessageDelayed(ubmsg, 10000);            }        } else {            // There are more pending requests in queue.            // Just post MCS_BOUND message to trigger processing of next pending install.            // 如果还有安装信息,则继续发送MCS_BOUND消息            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;}
MCS_BOUND消息的处理过程:调用InstallParams类的startCopy()方法来执行拷贝操作。只要mPendingInstalls中还有安装信息,就会重复发送MCS_BOUND消息,直到所有的应用都安装完毕,然后在发送一个延时10秒的MCS_UNBIND消息。(这块再来个流程图看的明显一些)

2.2.1 MCS_UNBOUND

case MCS_UNBIND: {    // If there is no actual work left, then time to unbind.    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");    if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {        if (mBound) {            if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");            disconnectService();        }    } else if (mPendingInstalls.size() > 0) {        // There are more pending requests in queue.        // Just post MCS_BOUND message to trigger processing of next pending install.        mHandler.sendEmptyMessage(MCS_BOUND);    }    break;}
MCS_UNBIND消息的处理过程:当mPendingInstalls中没有安装信息的时候,就调用disconnectService方法断开与DefaultContainerService的连接;如果发现还有安装信息,则继续发送MCS_BOUND消息。

2.3 拷贝方法startCopy

final boolean startCopy() {boolean res;try {if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);if (++mRetries > MAX_RETRIES) {// MAX_RETRIES为4Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");mHandler.sendEmptyMessage(MCS_GIVE_UP);handleServiceError();return false;} else {handleStartCopy();//展开2.3.1res = true;}} catch (RemoteException e) {if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");mHandler.sendEmptyMessage(MCS_RECONNECT);res = false;}handleReturnCode();//会尝试重新绑定 展开,详见3return res;}
startCopy()方法通过调用其子类InstallParams的handleStartCopy()来完成拷贝操作。startCopy主要工作是进行错误处理,当捕获到handleStartCopy跑出的异常时,startCopy将发送MCS_RECONNECT消息。在对MCS_RECONNECT消息的处理中,将会重新绑定DefaultContainerService,如果绑定成功,那安装过程将会重新开始。startCopy也将会再次被调用,重试的次数记录在mRetries中,当累计重试超过4次时,安装将失败。如果安装失败,那么startCopy将会调用handleReturnCode()来继续处理。

2.3.1 handleStartCopy

public void handleStartCopy() throws RemoteException{int ret = PackageManager.INSTALL_SUCCEEDED;// If we're already staged, we've firmly committed to an install location// 新安装时staged为false,前面在创建origin时,传入的false// final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile); 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");}}// 检查安装到哪里,SD卡还是内部final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;//精简版PackageInfoPackageInfoLite pkgLite = null;// 如果同时设置了安装在内部存储中和外部SD中,则报错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);//检查存储空间是否够安装该app,不够的话,执行如下分支if (!origin.staged && pkgLite.recommendedInstallLocation                == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {// TODO: focus freeing disk space on the target devicefinal StorageManager storage = StorageManager.from(mContext);final long lowThreshold = storage.getStorageLowBytes(Environment.getDataDirectory());final long sizeBytes = mContainerService.calculateInstalledSize(                    origin.resolvedPath, isForwardLocked(), packageAbiOverride);//尝试释放一些cache空间if (mInstaller.freeCache(null, sizeBytes + lowThreshold) >= 0) {//然后重新获取PackageInfoLitepkgLite = 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) {//如果上面这些步骤没报错的话,再判断pkgLite的信息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 == PackageHehandleStartCopylper.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 flagsif (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 unsetinstallFlags |= PackageManager.INSTALL_INTERNAL;installFlags &= ~PackageManager.INSTALL_EXTERNAL;}}}}// 其中abiOverride为null,创建一个安装参数对象final InstallArgs args = createInstallArgs(this);//=====2.3.1.1展开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)) {//此处是进行校验,一大段代码..................................} 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;}
handleStartCopy()方法会判断该app应该安装到哪里,如果安装空间不足的话,会尝试在清理一些cache空间后,再次尝试安装。该方法中很多代码是在将一些信息通过发送Intent android.intent.action.PACKAGE_NEEDS_VERIFICATION 给系统中所有接收该Intent进行处理。如果不需要校验的话,就直接调用InstallArgs的copyApk()方法。主要流程如图所示:


2.3.1.1 createInstallArgs

private InstallArgs createInstallArgs(InstallParams params) {if (params.move != null) {// 移动appreturn new MoveInstallArgs(params);} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {// 安装在SDreturn new AsecInstallArgs(params);} else {// 安装在内部存储return new FileInstallArgs(params);}}
此处讨论安装在内部存储的,所以创建的就是FileInstallArgs了,那么调用的copyApk,也是FileInstallArgs的了。

copyApk主要是对apk内容进行拷贝,FileInstallArgs.copyApk的数据流如下:

创建data/app下的目录并修改权限为755

拷贝base.apk(DefaultContainerService.java里的copypackage函数,里用copyfile函数 构建输入输出流,调用Stream的方法进行拷贝)

拷贝so文件


3. 装载应用

在前面的处理MCS_BOUND时调用的HandlerParams的startCopy方法(2.3小节)中当复制完文件之后,会调用InstallParams的handleReturnCode方法。

3.1 handleReturnCode:

void handleReturnCode() {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() {//向mHandler发一个Runnable对象,异步public void run() {mHandler.removeCallbacks(this);// Result object to be returnedPackageInstalledInfo res = new PackageInstalledInfo();res.returnCode = currentStatus;res.uid = -1;res.pkg = null;if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//欲安装阶段,主要是检查安装包的状态和安装环境,如果有问题就清理拷贝文件args.doPreInstall(res.returnCode);synchronized (mInstallLock) {installPackageLI(args, res);//安装阶段, 展开详见3.2}// 安装失败时,删除/data/app/包名中的内容args.doPostInstall(res.returnCode, res.uid);}            .....................................            // 用InstallArgs和PackageInstalledInfo构造一个PostInstallData对象,然后存放在mRunningInstalls里面 // 这样之后通过mRunningInstalls这个SparseArray查询就行// 如果安装成功&需要备份,则调用BackupManagerService来完成备份,并设置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);//展开详见3.3mHandler.sendMessage(msg);}}});}
processPendingInstall()方法中post了一个消息,这样安装过程将以异步的方式继续执行。在post消息中,首先是调用installPackageLI()来装载应用,接下来的一大段代码是在执行设备备份操作,备份是通过BackupManagerService来完成的,暂不分析。备份完成之后,通过发送POST_INSTALL消息继续处理。

3.2 installPackageLI[重要]

分析在代码注释中

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {//此段做了一些初始化值的工作final int installFlags = args.installFlags;//记录了app需要安装到哪里    final String installerPackageName = args.installerPackageName;// 安装程序的包名    final String volumeUuid = args.volumeUuid;// 与sd卡安装有关,一般为null    final File tmpPackageFile = new File(args.getCodePath());// 前面copyApk中的临时阶段性文件夹/data/app/vmdl<安装回话id>.tmp/这个目录了    final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);// 没有设定INSTALL_FORWARD_LOCK    final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)// 是否安装到外部存储            || (args.volumeUuid != null));    boolean replace = false;// 初始化替换flag为假    int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;// 设置浏览参数    if (args.move != null) {// 我们不是移动app,所以为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;//此段解析APK,也就是解析AndroidMainifest.xml文件,将结果记录在PackageParser.Package中    if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);    // Retrieve PackageSettings and parse package    // 设置解析apk的flags    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 {    // 开始解析apk,传入tmpPackageFile为一个文件夹        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;        }    }//此段搜集apk的签名信息,这块具体实现 待看.有两篇blog    try {        pp.collectCertificates(pkg, parseFlags);        pp.collectManifestDigest(pkg);    } catch (PackageParserException e) {        res.setError("Failed collect during installPackageLI", e);        return;    }// 如果安装程序此前传入了一个清单文件,那么将解析到的清单文件与传入的进行对比。//安装器的确传入了一个清单,PackageInstallerActivity中也解析了apk,那时记录了这个清单,并一并传入到这里了。//这里又做了一步判断,判断两者是同一个apk.    /* 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) {        // // 如果安装已经存在的应用的时候,PackageInstaller应用安装器会在会在installFlags中设置INSTALL_REPLACE_EXISTING        if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {            // 看看要替换的apk的包名是否存在原始包名            // 当app升级导致前后包名不一致的时候,需要记录仍然是原始包名,            // 所以这里要先检查要覆盖的app是否是这样的情况,是的话设置包名为旧的包名            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            // 当一个app按照6.0来编译的话,需要按照6.0的规则来解析app的权限。            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;                }            }        }createDataDirsLI方法中调用mInstaller.install安装---->例如mActivities.addActivity(..) 把四大组件信息注册到PMS内部        PackageSetting ps = mSettings.mPackages.get(pkgName);// 如果ps不为null,同样说明,已经存在一个同包名的程序被安装,也就是还是处理覆盖安装的情况// 这里主要是验证包名的签名,不一致的话,是不能覆盖安装的,另外版本号也不能比安装的低,否则也不能安装        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 {//ps是已有的. pkg是新安装的. 检查签名// 该函数分两步:// 如果有老版本的签名 则检查老版本的签名和新安装包的签名是否一致// 如果有共享用户的签名,则检查共享用户的签名与新安装包的签名是否一致。// 每一步都是三重机制:判断两个ArraySet是否相同->是否因为版本问题->恢复下证书(担心因为有变动)再试着比对一次 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        // 此段 检查apk中定义的权限是否已被其他应用定义过,如果重定义的是系统应用定义的权限,那么忽略本app定义的这个权限;如果重定义的是非系统应用的权限,则本次安装失败。        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);                    }                } else if (!"android".equals(pkg.packageName)) {                    // Prevent apps to change protection level to dangerous from any other                    // type as this would allow a privilege escalation where an app adds a                    // normal/signature permission in other app's group and later redefines                    // it as dangerous leading to the group auto-grant.                    if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)                            == PermissionInfo.PROTECTION_DANGEROUS) {                        if (bp != null && !bp.isRuntime()) {                            Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "                                    + "non-runtime permission " + perm.info.name                                    + " to runtime; keeping old protection level");                            perm.info.protectionLevel = bp.protectionLevel;                        }                    }                }            }        }    }//此段 当一个app是系统应用,但又希望安装在外部存储,那么就报错。    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;    }// 我们不是在移动app,所以不走这个分支,走else if分支    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()) {        // 设置SCAN_NO_DEX,这样在这个阶段就不会执行dexopt        scanFlags |= SCAN_NO_DEX;        try {//apk包里lib目录下有.so文件的,可以通过.so文件的ABI来确定app的primaryCpuAbi的值            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 */);        if (result == PackageDexOptimizer.DEX_OPT_FAILED) {            res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);            return;        }    }cc//重命名 将/data/app/vmdl<安装会话id>.tmp重命名为/data/app/包名-suffix,suffix为1,2...同时更新pkg中的受影响的字段。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);        }    }}

执行完installPackageLI之后,返回processPendingInstall方法中。

3.3 发送POST_INSTALL消息并处理

case POST_INSTALL: {    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);    //Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); 所以msg.arg1是token    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.removedPackage != null 即如果是更新, 还会发送"ACTION_PACKAGE_REMOVED"广播            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 AVAILABLE");                    }                    int[] uidArray = new int[] { res.pkg.applicationInfo.uid };                    ArrayList pkgList = new ArrayList(1);                    pkgList.add(packageName);                    //发送app->SD的资源更改广播                    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            //如果是首次安装浏览器APP,则重置浏览器设置            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        //GC操作        Runtime.getRuntime().gc();        // We delete after a gc for applications  on sdcard.        if (deleteOld) {            synchronized (mInstallLock) {                res.removedInfo.args.doPostDeleteLI(true);            }        }        //回调args.observer.packageInstalled方法。        //告诉PackageInstaller安装结果,从而实现了安装回调到UI层。        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;
该消息的处理主要就是在发送广播(很多个),应用安装完成之后要通知系统中的其他应用开始处理,安装到此结束~

更多相关文章

  1. Android(安卓)Day08四大组件之服务Service
  2. AndroidManifest.xml--android系统权限定义
  3. 杂乱之android的字体相关类Typeface
  4. Android常见错误之[email&#160;protected] that was originally
  5. Android中读取中文字符的文件与文件读取相关
  6. 如何将ADT(eclipse)开发工具锁定到LaucherPad启动器上
  7. Android(安卓)Activity中启动另一应用程序的方法,无需类名
  8. 转Launcher研究之AndroidManifest.xml分析(二)
  9. Android内部存储改变读取权限

随机推荐

  1. android web services
  2. android常见技巧---Android按返回键退出
  3. 3D相册图片滑动+倾斜+放大+倒影处理
  4. android 6.0 不弹允许usb调试 授权对话框
  5. android读取plist文件
  6. 使用Android自带的DownloadManager下载文
  7. android webview css z-index属性无效
  8. android中去掉ActionBar或TabWidget的分
  9. Android用HTTP下载报错“android.os.Stri
  10. Android Studio中Edittext监听回车事件,