android packagemanagerservice目录,Android重学系列 PackageManagerService的启动与安装(下)

前言

PMS installStage PMS中的安装步骤

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

final InstallParams params = new InstallParams(origin, null, observer,

sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,

verificationInfo, user, sessionParams.abiOverride,

sessionParams.grantedRuntimePermissions, signingDetails, installReason);

msg.obj = params;

...

mHandler.sendMessage(msg);

}

static OriginInfo fromStagedFile(File file) {

return new OriginInfo(file, true, false);

}

private OriginInfo(File file, boolean staged, boolean existing) {

this.file = file;

this.staged = staged;

this.existing = existing;

if (file != null) {

resolvedPath = file.getAbsolutePath();

resolvedFile = file;

} else {

resolvedPath = null;

resolvedFile = null;

}

}

很见到就是发送了一个INIT_COPY的handler消息,并且把stagedDir信息存储到OriginInfo中。OriginInfo记录了stageDir的路径也就是/data/app/vmdlsessionId.tmp

PackageHandler 处理INIT_COPY消息

case INIT_COPY: {

HandlerParams params = (HandlerParams) msg.obj;

int idx = mPendingInstalls.size();

if (!mBound) {

if (!connectToService()) {

params.serviceError();

return;

} else {

mPendingInstalls.add(idx, params);

}

} else {

mPendingInstalls.add(idx, params);

if (idx == 0) {

mHandler.sendEmptyMessage(MCS_BOUND);

}

}

}

首先第一次安装的时候mBound必定是false,就会调用connectToService尝试的绑定一个Service,如果绑定成功则把此时的安装参数HandlerParams保存到mPendingInstalls。

PackageHandler connectToService

public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(

DEFAULT_CONTAINER_PACKAGE,

"com.android.defcontainer.DefaultContainerService");

private boolean connectToService() {

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;

}

能看到此时先提高进程优先级到THREAD_PRIORITY_DEFAULT;并启动了一个DefaultContainerService服务,同时绑定了mDefContainerConn。成功后把进程设置回THREAD_PRIORITY_BACKGROUND。

class DefaultContainerConnection implements ServiceConnection {

public void onServiceConnected(ComponentName name, IBinder service) {

final IMediaContainerService imcs = IMediaContainerService.Stub

.asInterface(Binder.allowBlocking(service));

mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));

}

public void onServiceDisconnected(ComponentName name) {

}

}

值得注意的是,DefaultContainerConnection会监听Service启动后返回的Binder并且发送一个MCS_BOUND消息。

DefaultContainerService的Binder对象

实际上我们不需要关系这哥Service是启动都做了什么,我们关心的是返回的Binder是什么,具体的实现先不看,直接看看它的aidl接口

interface IMediaContainerService {

int copyPackage(String packagePath, in IParcelFileDescriptorFactory target);

PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, String abiOverride);

ObbInfo getObbInfo(String filename);

void clearDirectory(String directory);

long calculateInstalledSize(String packagePath, String abiOverride);

}

很简单,就是关于PMS中进行apk包相关的操作。

PackageHandler 处理MCS_BOUND消息

case MCS_BOUND: {

if (msg.obj != null) {

mContainerService = (IMediaContainerService) msg.obj;

}

if (mContainerService == null) {

...

} else if (mPendingInstalls.size() > 0) {

HandlerParams params = mPendingInstalls.get(0);

if (params != null) {

if (params.startCopy()) {

if (mPendingInstalls.size() > 0) {

mPendingInstalls.remove(0);

}

if (mPendingInstalls.size() == 0) {

if (mBound) {

removeMessages(MCS_UNBIND);

Message ubmsg = obtainMessage(MCS_UNBIND);

sendMessageDelayed(ubmsg, 10000);

}

} else {

mHandler.sendEmptyMessage(MCS_BOUND);

}

}

}

} else {

...

}

break;

}

能看到在PMS的ServiceThread handleThread线程中会检查mPendingInstalls是否有需要安装的对象,有则从mPendingInstalls的头部获取HandlerParams,调用HandlerParams.startCopy方法进行拷贝,知道消费完mPendingInstalls中所有的任务则进行解绑。

PMS.HandlerParams startCopy

private static final int MAX_RETRIES = 4;

final boolean startCopy() {

boolean res;

try {

if (++mRetries > MAX_RETRIES) {

mHandler.sendEmptyMessage(MCS_GIVE_UP);

handleServiceError();

return false;

} else {

handleStartCopy();

res = true;

}

} catch (RemoteException e) {

mHandler.sendEmptyMessage(MCS_RECONNECT);

res = false;

}

handleReturnCode();

return res;

}

在这个拷贝的步骤会重新的尝试4次,但是正常步骤则是调用handleStartCopy开始拷贝安装后,再调用handleReturnCode返回状态码

PMS.HandlerParams handleStartCopy

public void handleStartCopy() throws RemoteException {

int ret = PackageManager.INSTALL_SUCCEEDED;

if (origin.staged) {

if (origin.file != null) {

installFlags |= PackageManager.INSTALL_INTERNAL;

installFlags &= ~PackageManager.INSTALL_EXTERNAL;

} else {

}

}

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) {

...

} else if (onSd && ephemeral) {

...

} else {

pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,

packageAbiOverride);

...

}

...

final InstallArgs args = createInstallArgs(this);

mArgs = args;

if (ret == PackageManager.INSTALL_SUCCEEDED) {

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)) {

final Intent verification = new Intent(

Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);

verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),

PACKAGE_MIME_TYPE);

verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

final List receivers = queryIntentReceiversInternal(verification,

PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),

false /*allowDynamicSplits*/);

final int verificationId = mPendingVerificationToken++;

verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);

verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,

installerPackageName);

verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,

installFlags);

verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,

pkgLite.packageName);

verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,

pkgLite.versionCode);

verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,

pkgLite.getLongVersionCode());

if (verificationInfo != null) {

if (verificationInfo.originatingUri != null) {

verification.putExtra(Intent.EXTRA_ORIGINATING_URI,

verificationInfo.originatingUri);

}

if (verificationInfo.referrer != null) {

verification.putExtra(Intent.EXTRA_REFERRER,

verificationInfo.referrer);

}

if (verificationInfo.originatingUid >= 0) {

verification.putExtra(Intent.EXTRA_ORIGINATING_UID,

verificationInfo.originatingUid);

}

if (verificationInfo.installerUid >= 0) {

verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,

verificationInfo.installerUid);

}

}

final PackageVerificationState verificationState = new PackageVerificationState(

requiredUid, args);

mPendingVerification.append(verificationId, verificationState);

final List sufficientVerifiers = matchVerifiers(pkgLite,

receivers, verificationState);

DeviceIdleController.LocalService idleController = getDeviceIdleController();

final long idleDuration = getVerificationTimeout();

if (sufficientVerifiers != null) {

final int N = sufficientVerifiers.size();

if (N == 0) {

ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;

} else {

for (int i = 0; i < N; i++) {

final ComponentName verifierComponent = sufficientVerifiers.get(i);

idleController.addPowerSaveTempWhitelistApp(Process.myUid(),

verifierComponent.getPackageName(), idleDuration,

verifierUser.getIdentifier(), false, "package verifier");

final Intent sufficientIntent = new Intent(verification);

sufficientIntent.setComponent(verifierComponent);

mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);

}

}

}

final ComponentName requiredVerifierComponent = matchComponentForVerifier(

mRequiredVerifierPackage, receivers);

if (ret == PackageManager.INSTALL_SUCCEEDED

&& mRequiredVerifierPackage != null) {

verification.setComponent(requiredVerifierComponent);

idleController.addPowerSaveTempWhitelistApp(Process.myUid(),

mRequiredVerifierPackage, idleDuration,

verifierUser.getIdentifier(), false, "package verifier");

mContext.sendOrderedBroadcastAsUser(verification, verifierUser,

android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,

new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

final Message msg = mHandler

.obtainMessage(CHECK_PENDING_VERIFICATION);

msg.arg1 = verificationId;

mHandler.sendMessageDelayed(msg, getVerificationTimeout());

}

}, null, 0, null, null);

mArgs = null;

}

} else {

ret = args.copyApk(mContainerService, true);

}

}

mRet = ret;

}

1.调用IMediaContainerService的getMinimalPackageInfo方法,扫描安装apk到Android系统中。

2.通过createInstallArgs构建InstallArgs对象,如果getMinimalPackageInfo的安装成功了,则会进行判断该包是否已经安装过且isVerificationEnabled是否允许进行包校验器进行校验。

private InstallArgs createInstallArgs(InstallParams params) {

if (params.move != null) {

return new MoveInstallArgs(params);

} else {

return new FileInstallArgs(params);

}

}

注意我们此时是FileInstallArgs,我们只考虑第一次安装apk包的情况

3.如果可以进行包校验,则通过data为"application/vnd.android.package-archive"调用queryIntentReceiversInternal方法查找有没有注册在Android系统中的包校验广播接受者;通过matchVerifiers筛选出当前合适的包校验器,最后依次发送广播,让包校验接受者根据包名,versionCode,packageName,安装来源等信息进行校验

4.不如出现不满足进行校验的条件,则调用InstallArgs.copyApk进行进一步的拷贝操作。

关于包校验器这里就不多聊了,核心是第1点和第4点,让我们依次看看IMediaContainerService.getMinimalPackageInfo以及InstallArgs.copyApk

DefaultContainerService getMinimalPackageInfo

public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,

String abiOverride) {

final Context context = DefaultContainerService.this;

PackageInfoLite ret = new PackageInfoLite();

final File packageFile = new File(packagePath);

final PackageParser.PackageLite pkg;

final long sizeBytes;

try {

pkg = PackageParser.parsePackageLite(packageFile, 0);

sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);

} catch (PackageParserException | IOException e) {

...

}

final int recommendedInstallLocation;

final long token = Binder.clearCallingIdentity();

try {

recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,

pkg.packageName, pkg.installLocation, sizeBytes, flags);

} finally {

Binder.restoreCallingIdentity(token);

}

ret.packageName = pkg.packageName;

ret.splitNames = pkg.splitNames;

ret.versionCode = pkg.versionCode;

ret.versionCodeMajor = pkg.versionCodeMajor;

ret.baseRevisionCode = pkg.baseRevisionCode;

ret.splitRevisionCodes = pkg.splitRevisionCodes;

ret.installLocation = pkg.installLocation;

ret.verifiers = pkg.verifiers;

ret.recommendedInstallLocation = recommendedInstallLocation;

ret.multiArch = pkg.multiArch;

return ret;

}

1.PackageParser.parsePackageLite 对apk包进行解析

2.PackageHelper.calculateInstalledSize 对安装后的包进行大小统计

3.PackageHelper.resolveInstallLocation 计算出返回的结果

PackageParser.parsePackageLite

public static PackageLite parsePackageLite(File packageFile, int flags)

throws PackageParserException {

if (packageFile.isDirectory()) {

return parseClusterPackageLite(packageFile, flags);

} else {

return parseMonolithicPackageLite(packageFile, flags);

}

}

到这个方法就是解析包中的AndroidManifest最外层的数据.拿到版本号,包名,包的路径等等不包含四大组件的基础信息。注意这里将会走目录的分支,parseClusterPackageLite。这个方法其实和parseMonolithicPackageLite作用十分相似,核心还是遍历这个目录里面所有的apk文件,以splitName为key,ApkLite为value保存起来,并且找出null为key对应的baseApk的value,从而确认这个apk安装包的基础包是什么。

PackageHelper.calculateInstalledSize

public static long calculateInstalledSize(PackageLite pkg, NativeLibraryHelper.Handle handle,

String abiOverride) throws IOException {

long sizeBytes = 0;

for (String codePath : pkg.getAllCodePaths()) {

final File codeFile = new File(codePath);

sizeBytes += codeFile.length();

}

sizeBytes += DexMetadataHelper.getPackageDexMetadataSize(pkg);

sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);

return sizeBytes;

}

计算结果是:

安装后大小 = 每一个包安装路径下文件的大小(/data/app/vmdlsessionId.tmp/base.apk)+ .dm后缀的文件大小 + so库大小

FileInstallArgs.copyApk

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) {

codeFile = origin.file;

resourceFile = origin.file;

return PackageManager.INSTALL_SUCCEEDED;

}

try {

final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;

final File tempDir =

mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);

codeFile = tempDir;

resourceFile = tempDir;

} catch (IOException e) {

...

}

final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {

@Override

public ParcelFileDescriptor open(String name, int mode) throws RemoteException {

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) {

}

}

};

int ret = PackageManager.INSTALL_SUCCEEDED;

ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);

if (ret != PackageManager.INSTALL_SUCCEEDED) {

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) {

...

} finally {

IoUtils.closeQuietly(handle);

}

return ret;

}

1.PackageInstallerService.allocateStageDirLegacy 获取一个全新的sessionId对应目录:/data/app/vmdlsessionId.tmp/目录,把code和资源的路径都设置到同一处。

2.实例化一个IParcelFileDescriptorFactory接口,用于设置每一个创建文件时候确定权限为0644。

3.IMediaContainerService.copyPackage 把保存在OriginInfo的File(/data/app/vmdlsessionId.tmp/)拷贝到IParcelFileDescriptorFactory的路径中。

3.codeFile 下设置一个lib文件夹,里面包含了不同平台的so库。

IMediaContainerService.copyPackage

核心方法如下:

public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {

if (packagePath == null || target == null) {

return PackageManager.INSTALL_FAILED_INVALID_URI;

}

PackageLite pkg = null;

try {

final File packageFile = new File(packagePath);

pkg = PackageParser.parsePackageLite(packageFile, 0);

return copyPackageInner(pkg, target);

} catch (PackageParserException | IOException | RemoteException e) {

...

}

}

private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)

throws IOException, RemoteException {

copyFile(pkg.baseCodePath, target, "base.apk");

if (!ArrayUtils.isEmpty(pkg.splitNames)) {

for (int i = 0; i < pkg.splitNames.length; i++) {

copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");

}

}

return PackageManager.INSTALL_SUCCEEDED;

}

把/data/app/vmdlsessionId.tmp/下的文件apk资源往另一个sessionId对应的/data/app/vmdlsessionId.tmp/base.apk复制拷贝。

PMS.HandlerParams handleReturnCode

void handleReturnCode() {

if (mArgs != null) {

processPendingInstall(mArgs, mRet);

}

}

private void processPendingInstall(final InstallArgs args, final int currentStatus) {

mHandler.post(new Runnable() {

public void run() {

mHandler.removeCallbacks(this);

PackageInstalledInfo res = new PackageInstalledInfo();

res.setReturnCode(currentStatus);

res.uid = -1;

res.pkg = null;

res.removedInfo = null;

if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {

args.doPreInstall(res.returnCode);

synchronized (mInstallLock) {

installPackageTracedLI(args, res);

}

args.doPostInstall(res.returnCode, res.uid);

}

....

if (!doRestore) {

Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);

mHandler.sendMessage(msg);

}

});

}

1.InstallArgs.doPreInstall 安装失败则清除安装过程中的临时文件

2.installPackageTracedLI 安装扫描apk包

3.InstallArgs.doPostInstall 清除缓存在Installd的缓存

4.发送POST_INSTALL Handler消息到ServiceThread中处理

PMS installPackageTracedLI

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {

...

final PackageParser pp = new PackageParser();

pp.setSeparateProcesses(mSeparateProcesses);

pp.setDisplayMetrics(mMetrics);

pp.setCallback(mPackageParserCallback);

final PackageParser.Package pkg;

try {

pkg = pp.parsePackage(tmpPackageFile, parseFlags);

DexMetadataHelper.validatePackageDexMetadata(pkg);

} catch (PackageParserException e) {

...

} finally {

...

}

...

if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {

pkg.cpuAbiOverride = args.abiOverride;

}

String pkgName = res.name = pkg.packageName;

...

try {

if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {

pkg.setSigningDetails(args.signingDetails);

} else {

PackageParser.collectCertificates(pkg, false /* skipVerify */);

}

} catch (PackageParserException e) {

res.setError("Failed collect during installPackageLI", e);

return;

}

...

pp = null;

String oldCodePath = null;

boolean systemApp = false;

synchronized (mPackages) {

...

PackageSetting ps = mSettings.mPackages.get(pkgName);

if (ps != null) {

...

}

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 ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0

&& !systemApp) {

perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;

}

if (bp != null) {

final boolean sigsOk;

final String sourcePackageName = bp.getSourcePackageName();

final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();

final KeySetManagerService ksms = mSettings.mKeySetManagerService;

if (sourcePackageName.equals(pkg.packageName)

&& (ksms.shouldCheckUpgradeKeySetLocked(

sourcePackageSetting, scanFlags))) {

sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);

} else {

if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(

pkg.mSigningDetails,

PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {

sigsOk = true;

} else if (pkg.mSigningDetails.checkCapability(

sourcePackageSetting.signatures.mSigningDetails,

PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {

sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;

sigsOk = true;

} else {

sigsOk = false;

}

}

if (!sigsOk) {

...

} else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {

if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)

== PermissionInfo.PROTECTION_DANGEROUS) {

if (bp != null && !bp.isRuntime()) {

perm.info.protectionLevel = bp.getProtectionLevel();

}

}

}

}

}

}

...

if (args.move != null) {

...

} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {

....

}

if (!args.doRename(res.returnCode, pkg, oldCodePath)) {

return;

}

if (PackageManagerServiceUtils.isApkVerityEnabled()) {

String apkPath = null;

synchronized (mPackages) {

final PackageSetting ps = mSettings.mPackages.get(pkgName);

if (ps != null && ps.isPrivileged()) {

apkPath = pkg.baseCodePath;

}

}

if (apkPath != null) {

final VerityUtils.SetupResult result =

VerityUtils.generateApkVeritySetupData(apkPath);

if (result.isOk()) {

FileDescriptor fd = result.getUnownedFileDescriptor();

try {

final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);

mInstaller.installApkVerity(apkPath, fd, result.getContentSize());

mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);

} catch (InstallerException | IOException | DigestException |

...

} finally {

IoUtils.closeQuietly(fd);

}

} else if (result.isFailed()) {

...

} else {

}

}

}

..

try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,

"installPackageLI")) {

if (replace) {

...

} else {

installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,

args.user, installerPackageName, volumeUuid, res, args.installReason);

}

}

mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));

final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)

&& !forwardLocked

&& !pkg.applicationInfo.isExternalAsec()

&& (!instantApp || Global.getInt(mContext.getContentResolver(),

Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)

&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);

if (performDexopt) {

DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,

REASON_INSTALL,

DexoptOptions.DEXOPT_BOOT_COMPLETE |

DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);

mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,

null /* instructionSets */,

getOrCreateCompilerPackageStats(pkg),

mDexManager.getPackageUseInfoOrDefault(pkg.packageName),

dexoptOptions);

}

BackgroundDexOptService.notifyPackageChanged(pkg.packageName);

synchronized (mPackages) {

final PackageSetting ps = mSettings.mPackages.get(pkgName);

if (ps != null) {

res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);

ps.setUpdateAvailable(false /*updateAvailable*/);

}

...

}

}

分为如下几步:

1.PackageParser.parsePackage 扫描apk包中完整的AndroidManifest.xml内容,并把解析的package结果缓存到磁盘和内存中

2.往Package对象中设置好签名信息

3.从Settings中获取是否有当前包名对应的PackageSetting 包配置信息,此时还没有则跳开这里的if。获取PermissionManagerService查询权限信息。如果还是能查到,说明是包的升级,此时会进行包权限的校验。判断前后两次是不是内部包含的包权限内容都是一致,而只是顺序变了。当然如果之前没有安装,或者内容不一致,都会触发KeySetManagerService的checkUpgradeKeySetLocked进行更新

4.调用InstallArgs.doRename 把当前的包的名字给更新了

5.判断当前是否允许对包进行校验,如果允许则调用VerityUtils.generateApkVeritySetupData 对包的签名进行校验,校验通过根路径则调用Installd服务进一步调用installApkVerity进行校验。详细就不说了

6.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) {

String pkgName = pkg.packageName;

synchronized(mPackages) {

final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);

if (renamedPackage != null) {

return;

}

if (mPackages.containsKey(pkgName)) {

return;

}

}

try {

PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,

System.currentTimeMillis(), user);

updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);

if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {

prepareAppDataAfterInstallLIF(newPackage);

} else {

...

}

} catch (PackageManagerException e) {

}

}

1.调用scanPackageTracedLI 扫描包内容,此时其实已经解析过一次包内容,在这里能直接获得缓存。

2.updateSettingsLI 更新Settings中的包配置对象也就是PackageSettings对象以及往Settings的package.list和package.xml写入配置内容。关于这两个文件可以阅读PackageManagerService的启动与安装(上)。

3.prepareAppDataAfterInstallLIF核心还是调用了prepareAppDataLeafLIF方法,关于这个方法还是可以阅读PackageManagerService的启动与安装(上)。

3.2.实际上就是给下面编译优化的结果文件,创建对应的目录在每一个包下面创建cache或者code_cache文件夹,并且生成加速dex2oat编译的.prof文件.

3.3另一点就是调用了Installd的fixupAppData方法,创建一个/data/user/用户id和/data/data目录,也就是我们常见的/data/user/0./data/user/用户id是/data/data的软链接

7.prepareAppProfiles 调用/system/bin/profman生成加速dex2oat编译的.prof文件

8.PackageDexOptimizer.performDexOpt 进行dexopt 对dex文件进行优化

我们再来看看其中核心的scanPackageTracedLI 以及InstallArgs.doRename

PMS scanPackageTracedLI

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,

long currentTime, UserHandle user) throws PackageManagerException {

PackageParser pp = new PackageParser();

pp.setSeparateProcesses(mSeparateProcesses);

pp.setOnlyCoreApps(mOnlyCore);

pp.setDisplayMetrics(mMetrics);

pp.setCallback(mPackageParserCallback);

final PackageParser.Package pkg;

try {

pkg = pp.parsePackage(scanFile, parseFlags);

} catch (PackageParserException e) {

} finally {

}

if (pkg.applicationInfo.isStaticSharedLibrary()) {

renameStaticSharedLibraryPackage(pkg);

}

return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);

}

这里面的很简单又一次的调用了parsePackage,这一次是直接从缓存中读取出了完成的package信息,接着调用scanPackageChildLI。

scanPackageChildLI

private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,

final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,

@Nullable UserHandle user)

throws PackageManagerException {

if ((scanFlags & SCAN_CHECK_ONLY) == 0) {

if (pkg.childPackages != null && pkg.childPackages.size() > 0) {

scanFlags |= SCAN_CHECK_ONLY;

}

} else {

scanFlags &= ~SCAN_CHECK_ONLY;

}

// Scan the parent

PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,

scanFlags, currentTime, user);

final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;

for (int i = 0; i < childCount; i++) {

PackageParser.Package childPackage = pkg.childPackages.get(i);

addForInitLI(childPackage, parseFlags, scanFlags,

currentTime, user);

}

if ((scanFlags & SCAN_CHECK_ONLY) != 0) {

return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);

}

return scannedPkg;

}

在这里面会不断的递归整个目录结构中所有的可能的子包。我们不需要理解也ok,关键是addForInitLI 对每一个安装包的package会进行一次初始化。这个方法对于新包来说核心的逻辑在于其中的scanPackageNewLI

scanPackageNewLI

private PackageParser.Package scanPackageNewLI(@NonNull PackageParser.Package pkg,

final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,

@Nullable UserHandle user) throws PackageManagerException {

...

scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);

synchronized (mPackages) {

...

boolean scanSucceeded = false;

try {

final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,

pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,

originalPkgSetting, realPkgName, parseFlags, scanFlags,

(pkg == mPlatformPackage), user);

final ScanResult result = scanPackageOnlyLI(request, mFactoryTest, currentTime);

if (result.success) {

commitScanResultsLocked(request, result);

}

scanSucceeded = true;

} finally {

...

}

}

return pkg;

}

核心是调用了commitScanResultsLocked,这个方法对把扫描后的内容同步到PackageSettings,等待后续的写入到缓存文件中。对于全新的包则会做如下处理:

if (newPkgSettingCreated) {

if (originalPkgSetting != null) {

mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);

}

mSettings.addUserToSettingLPw(pkgSetting);

if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {

mTransferedPackages.add(originalPkgSetting.name);

}

}

核心就是Settings的addUserToSettingLPw 为新的包分配全新的userId。

void addUserToSettingLPw(PackageSetting p) throws PackageManagerException {

if (p.appId == 0) {

p.appId = newUserIdLPw(p);

} else {

addUserIdLPw(p.appId, p, p.name);

}

if (p.appId < 0) {

...

}

}

在ApplicationInfo 没有记录appid也就是没有分配过userId的情况下,会调用newUserIdLPw进行分配

public static final int FIRST_APPLICATION_UID = 10000;

public static final int LAST_APPLICATION_UID = 19999;

private int newUserIdLPw(Object obj) {

final int N = mUserIds.size();

for (int i = mFirstAvailableUid; i < N; i++) {

if (mUserIds.get(i) == null) {

mUserIds.set(i, obj);

return Process.FIRST_APPLICATION_UID + i;

}

}

if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {

return -1;

}

mUserIds.add(obj);

return Process.FIRST_APPLICATION_UID + N;

}

实际上就查找当前的mUserIds中有多少空闲的uid,找到则拿到对应的index,设置UserId为:

uid = 10000 + index

InstallArgs.doRename

boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {

final File targetDir = codeFile.getParentFile();

final File beforeCodeFile = codeFile;

final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);

try {

Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());

} catch (ErrnoException e) {

return false;

}

if (!SELinux.restoreconRecursive(afterCodeFile)) {

return false;

}

codeFile = afterCodeFile;

resourceFile = afterCodeFile;

try {

pkg.setCodePath(afterCodeFile.getCanonicalPath());

} catch (IOException e) {

return false;

}

pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,

afterCodeFile, pkg.baseCodePath));

pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,

afterCodeFile, pkg.splitCodePaths));

// Reflect the rename in app info

pkg.setApplicationVolumeUuid(pkg.volumeUuid);

pkg.setApplicationInfoCodePath(pkg.codePath);

pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);

pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);

pkg.setApplicationInfoResourcePath(pkg.codePath);

pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);

pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);

return true;

}

在这里存在两种路径,一种是变化前的路径,名字为/data/app/vmdlsessionId/base.apk,另一种是安装后的路径,通过如下getNextCodePath方法获得:

private File getNextCodePath(File targetDir, String packageName) {

File result;

SecureRandom random = new SecureRandom();

byte[] bytes = new byte[16];

do {

random.nextBytes(bytes);

String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);

result = new File(targetDir, packageName + "-" + suffix);

} while (result.exists());

return result;

}

targetDir是指/data/app/vmdlsessionId.tmp/的父目录/data/app/ 那么此时就是设置为/data/app/包名-随机数

发送POST_INSTALL Handler消息到PackageHandler中处理

当安装完成后就会发送POST_INSTALL 处理安装完的内容

case POST_INSTALL: {

PostInstallData data = mRunningInstalls.get(msg.arg1);

final boolean didRestore = (msg.arg2 != 0);

mRunningInstalls.delete(msg.arg1);

if (data != null) {

InstallArgs args = data.args;

PackageInstalledInfo parentRes = data.res;

final boolean grantPermissions = (args.installFlags

& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;

final boolean killApp = (args.installFlags

& PackageManager.INSTALL_DONT_KILL_APP) == 0;

final boolean virtualPreload = ((args.installFlags

& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);

final String[] grantedPermissions = args.installGrantPermissions;

handlePackagePostInstall(parentRes, grantPermissions, killApp,

virtualPreload, grantedPermissions, didRestore,

args.installerPackageName, args.observer);

final int childCount = (parentRes.addedChildPackages != null)

? parentRes.addedChildPackages.size() : 0;

for (int i = 0; i < childCount; i++) {

PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);

handlePackagePostInstall(childRes, grantPermissions, killApp,

virtualPreload, grantedPermissions, false /*didRestore*/,

args.installerPackageName, args.observer);

}

} else {

}

} break;

核心方法是handlePackagePostInstall,这个方法发送了如下几种广播:

1.Intent.ACTION_PACKAGE_ADDED 包添加广播

2.Intent.ACTION_PACKAGE_REPLACED 包替换广播

最后还会获取到保存在InstallArgs的IPackageInstallObserver2 ,回调onPackageInstalled。也就是在PackageInstallSession的commit流程中生成的对象,而这个方法又会调用dispatchSessionFinished

PackageInstallSession dispatchSessionFinished

private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {

final IPackageInstallObserver2 observer;

final String packageName;

synchronized (mLock) {

mFinalStatus = returnCode;

mFinalMessage = msg;

observer = mRemoteObserver;

packageName = mPackageName;

}

if (observer != null) {

final SomeArgs args = SomeArgs.obtain();

args.arg1 = packageName;

args.arg2 = msg;

args.arg3 = extras;

args.arg4 = observer;

args.argi1 = returnCode;

mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();

}

final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);

final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);

if (success && isNewInstall) {

mPm.sendSessionCommitBroadcast(generateInfo(), userId);

}

mCallback.onSessionFinished(this, success);

}

做了三件事情:

1.发送Handler消息MSG_ON_PACKAGE_INSTALLED

2.发送了一个ACTION_SESSION_COMMITTED广播 发送到InstallEventReceiver

3.回调了onSessionFinished

其中第一点的MSG_ON_PACKAGE_INSTALLED的消息处理中又调用了Binder对象mRemoteObserver的onPackageInstalled。此时就会调用PackageInstallObserver也就是PackageInstallerService. PackageInstallObserverAdapter的onPackageInstalled。

PackageInstallObserverAdapter的onPackageInstalled

public void onPackageInstalled(String basePackageName, int returnCode, String msg,

Bundle extras) {

if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {

boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);

Notification notification = buildSuccessNotification(mContext,

mContext.getResources()

.getString(update ? R.string.package_updated_device_owner :

R.string.package_installed_device_owner),

basePackageName,

mUserId);

if (notification != null) {

NotificationManager notificationManager = (NotificationManager)

mContext.getSystemService(Context.NOTIFICATION_SERVICE);

notificationManager.notify(basePackageName,

SystemMessage.NOTE_PACKAGE_STATE,

notification);

}

}

final Intent fillIn = new Intent();

fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);

fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);

fillIn.putExtra(PackageInstaller.EXTRA_STATUS,

PackageManager.installStatusToPublicStatus(returnCode));

fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,

PackageManager.installStatusToString(returnCode, msg));

fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);

if (extras != null) {

final String existing = extras.getString(

PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);

if (!TextUtils.isEmpty(existing)) {

fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);

}

}

try {

mTarget.sendIntent(mContext, 0, fillIn, null, null);

} catch (SendIntentException ignored) {

}

}

}

能看到此时就会调用NotificationManager 出现一个通知栏告诉用户已经安装好了apk了。

InstallEventReceiver 接受到广播后的处理

当这个对象接受到广播后,就会调用EventResultPersister的onEventReceived

void onEventReceived(@NonNull Context context, @NonNull Intent intent) {

int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);

if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) {

context.startActivity(intent.getParcelableExtra(Intent.EXTRA_INTENT));

return;

}

int id = intent.getIntExtra(EXTRA_ID, 0);

String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);

int legacyStatus = intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 0);

EventResultObserver observerToCall = null;

synchronized (mLock) {

int numObservers = mObservers.size();

for (int i = 0; i < numObservers; i++) {

if (mObservers.keyAt(i) == id) {

observerToCall = mObservers.valueAt(i);

mObservers.removeAt(i);

break;

}

}

if (observerToCall != null) {

observerToCall.onResult(status, legacyStatus, statusMessage);

} else {

mResults.put(id, new EventResult(status, legacyStatus, statusMessage));

writeState();

}

}

}

这里很简单从EXTRA_ID 中获取当前EventResultObserver对应的id,并且回调onResult。此时就会回调到InstallInstalling的launchFinishBasedOnResult方法中。

InstallInstalling launchFinishBasedOnResult

private void launchFinishBasedOnResult(int statusCode, int legacyStatus, String statusMessage) {

if (statusCode == PackageInstaller.STATUS_SUCCESS) {

launchSuccess();

} else {

launchFailure(legacyStatus, statusMessage);

}

}

很简单就是显示成功或者失败的页面。

总结

到这里PMS的安装全流程就解析完了,虽然有不少的地方说不详细,但是总体架构在这里了,需要探索哪一点可以继续根据这个框架去阅读源码即可。老规矩,先上一个时序图,流程很长,注意这里我没有把所有的AysncTask中的流程显示出来,能意会就好:

033e6a9a3d7c

PMS安装流程.jpg

在PMS的安装过程,总结来说就是两个步骤:

1.拷贝apk

2.解析apk,把解析的内容缓存到Andoid系统,把包内容保存在配置中。

apk的拷贝过程,经过了如下几次变化,我们以此为线索梳理其流程:

1.来源apk uri -> /data/no_backup/packagexxx.apk .

2./data/no_backup/packagexxx.apk

-> /data/app/vmdlsessionId.tmp/PackageInstaller 这个过程中还记录了PackageInstallerSession的记录,保存在/data/system/install_sessions.xml 中。这个过程是通过PackageInstallerService创建一个Session对象时候进行记录,这样就能得知Android系统中曾经出现过多少次安装记录,可能出现多少残余的数据需要清除。

3./data/app/vmdlsessionId.tmp/PackageInstaller -> 会变化为另外一个sessionId对应的/data/app/vmdlsessionId.tmp/base.apk 这个过程因为可能会复用sessionId,因此需要先删除一些之前可能遗留下来的残留文件,接着就会创建一个临时的/data/app/vmdlsessionId.tmp/lib保存so库

4./data/app/vmdlsessionId2.tmp/base.apk 重命名为 /data/app/包名-随机数

在这个过程最为核心,就是整个PMS的安装核心如下:

4.1.PackageParser.parsePackage 解析包AndroidManifest所有内容,缓存到data/system/package_cache/包名_0中

4.2.scanPackageTracedLI 虽然这个方法也有扫描包内容的能力,但是这里更加重要的是为每一个apk包设置好PackageSettings对象,准备写入到Settings中packages.xml中,并为每一个新安装的apk设置好自己的userid(10000 + index).

4.3. updateSettingsLI 把包配置设置到packages.xml

4.4. prepareAppDataAfterInstallLIF, prepareAppProfiles,PackageDexOptimizer.performDexOpt都是对dex文件的优化提供环境:

4.4.1.prepareAppDataAfterInstallLIF提供目录结构/data/user/用户ID/包名/cache 或/data/user/用户ID/包名/code_cache

4.4.2.调用了Installd的fixupAppData方法,创建一个/data/user/用户id和/data/data目录,也就是我们常见的/data/user/0./data/user/用户id是/data/data的软链接

4.4.2.prepareAppProfiles 提供加速编译的文件

4.4.3.performDexOpt 执行dexopt

4.5. doRename 重命名

5.最后发送POST_INSTALL消息,通过IPackageInstallObserver2回调,通知此时又调用DefaultContainerService记录好的Binder的onPackageInstalled 展示一个通知栏通知,告诉用户已经安装完毕

6.IPackageInstallObserver2回调 回调中也会发送一个广播消息,告诉正在等待安装结果的InstallInstalling 页面展示安装成功提示。

后话

到这里PMS的全流程就结束了,能看到有一个很核心的内容,performDexOpt是是如何优化dex还没有聊到。这是一个比较重要的内容,但是学习的门槛有点高,需要熟悉ART 虚拟机。

不过没关系,我对ART虚拟机源码也来回看了几遍,之后我会开启新的篇章,名为JVM基础系列,让我们恶补一下关于Java的“基础”吧,看看网上哪些优化的言论,看看网上哪些常用的说法是否正确。要达到这个能力还需要自己亲自去底层看看ART是怎么设计的。通过对JVM的理解,可以加深对Java编程的理解。

在这之前,我会补上Activity和Binder的总结,以及一篇概述。之后的计划,应该是来总结网络相关的知识。就以解析OkHttp开始,看看socket的底层设计吧。等理解了socket,再来看看JVM相关的篇章吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值