Android6.0 PackageManagerService(PMS)-安装

本文详细介绍了Android 6.0中PackageManagerService(PMS)的安装过程,主要分为三个步骤:1)权限检查,调用enforceCrossUserPermission;2)复制文件,包括INIT_COPY、MCS_BOUND等阶段;3)装载应用,涉及handleReturnCode、installPackageLI等关键函数。整个安装过程中,文件复制和权限管理是核心环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

    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.1
	enforceCrossUserPermission(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为4
			Slog.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.1
			res = true;
		}
	} catch (RemoteException e) {
		if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
		mHandler.sendEmptyMessage(MCS_RECONNECT);
		res = false;
	}
	handleReturnCode();//会尝试重新绑定 展开,详见3
	return 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;

	//精简版PackageInfo
	PackageInfoLite 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 device
			final 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) {
				//然后重新获取PackageInfoLite
				pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                       installFlags, packageAbiOverride);
			}

			/*
			 * The cache free must have deleted the file we
             * downloaded to install.
             *
             * TODO: fix the "freeCache" call to not delete
             *       the file we care about.
             */
			if (pkgLite.recommendedInstallLocation
                    == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
				pkgLite.recommendedInstallLocation
                    = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
			}
		}
	}

	if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果上面这些步骤没报错的话,再判断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 flags
				if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
					// Set the flag to install on external media.
					installFlags |= PackageManager.INSTALL_EXTERNAL;
					installFlags &= ~PackageManager.INSTALL_INTERNAL;
				} else {
					// Make sure the flag for installing on external
					// media is unset
					installFlags |= PackageManager.INSTALL_INTERNAL;
					installFlags &= ~PackageManager.INSTALL_EXTERNAL;
				}
			}
		}
	}

	// 其中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) {
		// 移动app
		return new MoveInstallArgs(params);
	} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
		// 安装在SD
		return 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 returned
			PackageInstalledInfo 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.3
				mHandler.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<res.newUsers.length; i++) {
                    int user = res.newUsers[i];
                    boolean isNew = true;
                    for (int j=0; j<res.origUsers.length; j++) {
                        if (res.origUsers[j] == user) {
                            isNew = false;
                            break;
                        }
                    }
                    if (isNew) {
                        int[] newFirst = new int[firstUsers.length+1];
                        System.arraycopy(firstUsers, 0, newFirst, 0,
                                firstUsers.length);
                        newFirst[firstUsers.length] = user;
                        firstUsers = newFirst;
                    } else {
                        int[] newUpdate = new int[updateUsers.length+1];
                        System.arraycopy(updateUsers, 0, newUpdate, 0,
                                updateUsers.length);
                        newUpdate[updateUsers.length] = user;
                        updateUsers = newUpdate;
                    }
                }
            }

            //上述是判断哪些用户是首次安装,哪些用户是更新安装
            //发送一个ACTION_PACKAGE_ADDED广播(对首次安装的用户)
            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                    packageName, extras, null, null, firstUsers);
            final boolean update = res.removedInfo.removedPackage != null;
            //如果是更新,extra字段添加一下值
            if (update) {
                extras.putBoolean(Intent.EXTRA_REPLACING, true);
            }
            //发送一个ACTION_PACKAGE_ADDED广播(对更新的用户)
            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                    packageName, extras, null, null, updateUsers);
            //如果是更新,发送ACTION_PACKAGE_REPLACED和ACTION_MY_PACKAGE_REPLACED广播
            //sendPackageBroadcast的第四个参数是targetPkg
            if (update) {
                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                        packageName, extras, null, null, updateUsers);
                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                        null, null, packageName, null, updateUsers);

                // treat asec-hosted packages like removable media on upgrade
                //处理安装在SD卡的
                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
                    if (DEBUG_INSTALL) {
                        Slog.i(TAG, "upgrading pkg " + res.pkg
                                + " is ASEC-hosted -> AVAILABLE");
                    }
                    int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
                    ArrayList<String> pkgList = new ArrayList<String>(1);
                    pkgList.add(packageName);
                    //发送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;
该消息的处理主要就是在发送广播(很多个),应用安装完成之后要通知系统中的其他应用开始处理,安装到此结束~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值