Android系统的代码总是在不断迭代的,具体的类和方法本身并不重要,关键是了解流程与主要的路径
本文基于AOSP master分支 2020年8月,Android 11 已经处于beta版
三种安装方式
- 系统级app安装
- 普通app安装
- adb安装
这里看一下普通APP的安装.
在分析之前,想一下如果是我们来安装apk,需要怎么做:
apk实际上是一个zip包,先解压,要不然只能测量下大小了,当然也可以不解压直接查看zip包的内容
系统重启之后我们依然要快速显示和启动app,那么肯定得存一份APP信息到手机上,那么存什么信息呢?
- 可执行文件的位置,在Android里跑的是dex,或者dex处理过后的机器码,因此这里应该是dex或者oat文件的位置
- 应用有一些特殊的功能,比如可以用来打开文档,网页等,因此需要把这些信息注册到一个系统表里,可以快速查询,Android中应也有这么一个表
而且最好是把apk的资源,可执行文件等内部数据放到一个文件夹下,这样卸载的时候可以直接删除目录.
zip包解压了,信息也存了,为了安全,应该把对应的可执行文件和资源文件复制到指定的路径,如果有so库,还要让程序知道去哪里找so文件
检查手机上之前是否已经安装了这个app,如果安装了,比较一下版本,签名,再确定怎么处理
删除apk包以节省空间
APK解压缩
APK的解析在Java中的入口在PackageParser
中,但是实际解压的操作在Native层,也就是ApkAssets
中,ApkAssets
中会调用libziparchive库去解压缩APK.
int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
const int fd = ::android::base::utf8::open(fileName, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
ZipArchive* archive = new ZipArchive(MappedZipFile(fd), true);
*handle = archive;
if (fd < 0) {
ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
return kIoError;
}
return OpenArchiveInternal(archive, fileName);
}
int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
bool assume_ownership) {
ZipArchive* archive = new ZipArchive(MappedZipFile(fd), assume_ownership);
*handle = archive;
return OpenArchiveInternal(archive, debug_file_name);
}
static int32_t OpenArchiveInternal(ZipArchive* archive, const char* debug_file_name) {
int32_t result = MapCentralDirectory(debug_file_name, archive);
return result != kSuccess ? result : ParseZipArchive(archive);
}
int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
bool assume_ownership) {
ZipArchive* archive = new ZipArchive(MappedZipFile(fd), assume_ownership);
*handle = archive;
return OpenArchiveInternal(archive, debug_file_name);
}
解压的具体的过程就不分析了,使用解压库就行,来看下Manifest.xml信息的提取.
ApkAssets.java
中有:
public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
XmlResourceParser parser = block.newParser();
// If nativeOpenXml doesn't throw, it will always return a valid native pointer,
// which makes newParser always return non-null. But let's be paranoid.
if (parser == null) {
throw new AssertionError("block.newParser() returned a null parser");
}
return parser;
}
}
}
frameworks/base/core/jni/android_content_res_ApkAssets.cpp
中有:
static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
ScopedUtfChars path_utf8(env, file_name);
if (path_utf8.c_str() == nullptr) {
return 0;
}
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
// 这里就是打开Manifest文件的入口
std::unique_ptr<Asset> asset = apk_assets->Open(path_utf8.c_str(),
Asset::AccessMode::ACCESS_RANDOM);
if (asset == nullptr) {
jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
return 0;
}
// DynamicRefTable is only needed when looking up resource references. Opening an XML file
// directly from an ApkAssets has no notion of proper resource references.
std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
asset.reset();
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
}
return reinterpret_cast<jlong>(xml_tree.release());
}
在AppAssets.cpp
中有:
std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode mode) const {
CHECK(zip_handle_ != nullptr);
::ZipEntry entry;
// manifest 文件
int32_t result = ::FindEntry(zip_handle_.get(), path, &entry);
if (result != 0) {
return {};
}
// 判断压缩方式,是否使用的是Deflate压缩算法
if (entry.method == kCompressDeflated) {
std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset,
entry.compressed_length, true /*readOnly*/)) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
return {};
}
std::unique_ptr<Asset> asset =
Asset::createFromCompressedMap(std::move(map), entry.uncompressed_length, mode);
if (asset == nullptr) {
LOG(ERROR) << "Failed to decompress '" << path << "'.";
return {};
}
return asset;
} else {
// Store压缩方法,即不压缩
std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset,
entry.uncompressed_length, true /*readOnly*/)) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
return {};
}
std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map), mode);
if (asset == nullptr) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
return {};
}
return asset;
}
}
Android中的资源主要是Deflate和Stored两种压缩方式,其中Stored实际并不压缩数据,只是转换成字节数据存储而已.
Manifest.xml使用了Deflate压缩算法进行压缩,因此这里需要对应的解压出来.
其他的几个步骤,在零零碎碎的源码中找吧.
普通APP安装
先看一个简单的下载并安装apk的例子:
val intent = Intent(Intent.ACTION_VIEW)
intent.apply {
flags += Intent.FLAG_ACTIVITY_NEW_TASK
flags += Intent.FLAG_GRANT_READ_URI_PERMISSION
type = "application/vnd.android.package-archive"
data = FileProvider.getUriForFile(context, "com.jiangkang.ktools", file)
}
context.startActivity(intent)
这里使用ACTION_VIEW
,最终会调用到PacakgeInstaller APP中.
Android 10的PacakgeInstaller源码在framworks/base/packages/PackageInstaller下,看一下它的Manifest.xml来确定下谁是入口:
<activity android:name=".InstallStart"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_INSTALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
可以看到PackageInstaller支持的action以及协议,即content协议和package协议.
进入了InstallStart
之后,根据状态的不同可能会经过InstallStaging
等页面后进入到PacakgeInstallerActivity
,然后就是不同的安装进度了,InstallInstalling
,InstallFailed
,InstallSuccess
:
来看一下关键的对象:
PackageManager mPm = getPackageManager();;
PackageInstaller mInstaller = = mPm.getPackageInstaller();
final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
然后就是开始安装APP了:
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
// apk file uri
newIntent.setData(mPackageURI);
// 安装过程处理 Activity
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
来看下InstallInstalling中的处理逻辑:
ApplicationInfo appInfo = getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();
if ("package".equals(mPackageURI.getScheme())) {
// 使用pacakge协议,即package:com.xxx,安装手机上已有的APP
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
// 安装APK文件
// 将安装信息封装到SessionParams中
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallAsInstantApp(false);
params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
params.setOriginatingUri(getIntent()
.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN));
params.setInstallerPackageName(getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME));
params.setInstallReason(PackageManager.INSTALL_REASON_USER);
// apk文件
File file = new File(mPackageURI.getPath());
// 解析APK文件,获取APP信息
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
将信息保存到SessionParams中,并返回一个sessionId,后面会用到这个sessionid,在onResume的时候会启动一个后台任务去读取APK文件:
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
// 根据sessionID获取到之前存储的session
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
return null;
}
session.setStagingProgress(0);
// 读取APK文件
try {
File file = new File(mPackageURI.getPath());
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
session.fsync(out);
break;
}
if (isCancelled()) {
session.close();
break;
}
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);
session.close();
return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
// apk文件读取完毕
if (session != null) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(getPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 此处关键
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
这里主要是读取APK文件到Session中,并更新安装进度.读取完毕之后发送一个广播.
此处的关键是就是session.commit()
方法.
这里会调用PackageManagerService中.首先进入的是Copy阶段:
复制APK
void installStage(ActiveInstallSession activeInstallSession) {
// COPY 阶段
final Message msg = mHandler.obtainMessage(INIT_COPY);
final InstallParams params = new InstallParams(activeInstallSession);
msg.obj = params;
mHandler.sendMessage(msg);
}
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
params.startCopy();
}
break;
}
final void startCopy() {
handleStartCopy();
handleReturnCode();
}
这个copy阶段会进行一些判断,比如存储空间是否足够,如果不够会试图清理一下缓存,如果之前已经存在了APK,则直接覆盖,但是如果存在APK验证器,则必须在copy之前进行验证,只有验证通过之后才可以开始复制APK.
void handleReturnCode() {
if (mVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
try {
PackageLite packageInfo =
new PackageParser().parsePackageLite(origin.file, 0);
packageName = packageInfo.packageName;
} catch (PackageParserException e) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
return;
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// 复制APK
mRet = mArgs.copyApk();
}
// 复制完成之后进入下一阶段
processPendingInstall(mArgs, mRet);
}
}
}
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private int doCopyApk() {
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) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
// 实际复制操作
int ret = PackageManagerServiceUtils.copyPackage(
origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
// so文件
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
APK会被复制到/data/app下:
public static File getDataAppDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "app");
}
实际的copy过程如下,使用了FileDescriptor:
public static int copyPackage(String packagePath, File targetDir) {
if (packagePath == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
try {
final File packageFile = new File(packagePath);
// 解析APK文件
// 1. 解析Manifest文件,得到各种信息如版本号等
// 2. 收集签名信息
final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
// 复制到指定位置,并重命名为base.apk,一般为/data/app/packageName-xxx/base.apk
copyFile(pkg.baseCodePath, targetDir, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
for (int i = 0; i < pkg.splitNames.length; i++) {
copyFile(pkg.splitCodePaths[i], targetDir,
"split_" + pkg.splitNames[i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
} catch (PackageParserException | IOException | ErrnoException e) {
Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
}
private static void copyFile(String sourcePath, File targetDir, String targetName)
throws ErrnoException, IOException {
if (!FileUtils.isValidExtFilename(targetName)) {
throw new IllegalArgumentException("Invalid filename: " + targetName);
}
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
final File targetFile = new File(targetDir, targetName);
final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
Os.chmod(targetFile.getAbsolutePath(), 0644);
FileInputStream source = null;
try {
source = new FileInputStream(sourcePath);
FileUtils.copy(source.getFD(), targetFd);
} finally {
IoUtils.closeQuietly(source);
}
}
复制之前,会使用PacakgeParser
解析APK中的mannifest文件,得到一些应用信息,并且还会获取签名信息.
然后就是复制apk文件,并且复制APK中的so文件到指定的路径.
复制完成之后,进入下一阶段processPendingInstall(mArgs, mRet);
安装APK
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
对于包含split APP的安装过程暂时不分析,这里指分析单个完整APK的安装流程.
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
实际安装步骤在installPackagesLI(requests)
:
private void installPackagesLI(List<InstallRequest> requests) {
final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
final Map<String, PackageSetting> lastStaticSharedLibSettings =
new ArrayMap<>(requests.size());
final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
boolean success = false;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
// TODO(b/109941548): remove this once we've pulled everything from it and into
// scan, reconcile or commit.
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
prepareResult = preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
request.installResult.origPackage = prepareFailure.conflictingPackage;
request.installResult.origPermission = prepareFailure.conflictingPermission;
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
request.installResult.installerPackageName = request.args.installerPackageName;
final String packageName = prepareResult.packageToScan.packageName;
prepareResults.put(packageName, prepareResult);
installResults.put(packageName, request.installResult);
installArgs.put(packageName, request.args);
try {
final List<ScanResult> scanResults = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user);
for (ScanResult result : scanResults) {
if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.packageName
+ " in multi-package install request.");
return;
}
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.pkgSetting.pkg.packageName,
getSettingsVersionForPackage(result.pkgSetting.pkg));
if (result.staticSharedLibraryInfo != null) {
final PackageSetting sharedLibLatestVersionSetting =
getSharedLibLatestVersionSetting(result);
if (sharedLibLatestVersionSetting != null) {
lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
sharedLibLatestVersionSetting);
}
}
}
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mPackages) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.installResult.setError("Reconciliation failed...", e);
}
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
sUserManager.getUserIds());
commitPackagesLocked(commitRequest);
success = true;
} finally {
for (PrepareResult result : prepareResults.values()) {
if (result.freezer != null) {
result.freezer.close();
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
executePostCommitSteps(commitRequest);
} finally {
if (!success) {
for (ScanResult result : preparedScans.values()) {
if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
cleanUpAppIdCreation(result);
}
}
// TODO(patb): create a more descriptive reason than unknown in future release
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
for (PrepareResult result : prepareResults.values()) {
if (result.freezer != null) {
result.freezer.close();
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
这里分为4个步骤:
prepare
使用PackageParser解析APK,获取各种信息,检查是否有静态共享库,有的话放在内部存储中.决定安装方式(更新,还是新安装)之类的逻辑.
scan
扫描APK,更新共享库和Settings信息
reconcile
新旧包以及签名相关的逻辑
commit
更新设置
其实都是对APK文件进行一系列的检查验证,以确保最后可以安装成功.然后就是真实的安装了:
private void executePostCommitSteps(CommitRequest commitRequest) {
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
final String packageName = pkg.packageName;
prepareAppDataAfterInstallLIF(pkg);
if (reconciledPkg.prepareResult.clearCodeCache) {
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
if (reconciledPkg.prepareResult.replace) {
mDexManager.notifyPackageUpdated(pkg.packageName,
pkg.baseCodePath, pkg.splitCodePaths);
}
// Prepare the application profiles for the new code paths.
// This needs to be done before invoking dexopt so that any install-time profile
// can be used for optimizations.
mArtManagerService.prepareAppProfiles(
pkg,
resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
/* updateReferenceProfileContent= */ true);
// Check whether we need to dexopt the app.
//
// NOTE: it is IMPORTANT to call dexopt:
// - after doRename which will sync the package data from PackageParser.Package and
// its corresponding ApplicationInfo.
// - after installNewPackageLIF or replacePackageLIF which will update result with the
// uid of the application (pkg.applicationInfo.uid).
// This update happens in place!
//
// We only need to dexopt if the package meets ALL of the following conditions:
// 1) it is not an instant app or if it is then dexopt is enabled via gservices.
// 2) it is not debuggable.
//
// Note that we do not dexopt instant apps by default. dexopt can take some time to
// complete, so we skip this step during installation. Instead, we'll take extra time
// the first time the instant app starts. It's preferred to do it this way to provide
// continuous progress to the useur instead of mysteriously blocking somewhere in the
// middle of running an instant app. The default behaviour can be overridden
// via gservices.
final boolean performDexopt =
(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
if (performDexopt) {
// Compile the layout resources.
if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
mViewCompiler.compileLayouts(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Do not run PackageDexOptimizer through the local performDexOpt
// method because `pkg` may not be in `mPackages` yet.
//
// Also, don't fail application installs if the dexopt step fails.
DexoptOptions dexoptOptions = new DexoptOptions(packageName,
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
mPackageDexOptimizer.performDexOpt(pkg,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BackgroundDexOptService will remove it from its blacklist.
// TODO: Layering violation
BackgroundDexOptService.notifyPackageChanged(packageName);
}
}
这里主要分为两部:
- 调用Installer创建APP数据
- 如果so库是32为,创建symlink,64位的so库不需要
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, app.targetSdkVersion);
if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) {
final String nativeLibPath = app.nativeLibraryDir;
try {
mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
nativeLibPath, userId);
} catch (InstallerException e) {
Slog.e(TAG, "Failed to link native for " + packageName + ": " + e);
}
}
public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
String seInfo, int targetSdkVersion) throws InstallerException {
if (!checkBeforeRemote()) return -1;
try {
return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
targetSdkVersion);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
Installer
中的操作基本上都是委托给守护进程installd
去完成的.
Installer中通过Binder机制获取到intalld服务,真实的执行逻辑在native层:
private void connect() {
IBinder binder = ServiceManager.getService("installd");
if (binder != null) {
try {
binder.linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "installd died; reconnecting");
connect();
}
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
mInstalld = IInstalld.Stub.asInterface(binder);
try {
invalidateMounts();
} catch (InstallerException ignored) {
}
} else {
Slog.w(TAG, "installd not found; trying again");
BackgroundThread.getHandler().postDelayed(() -> {
connect();
}, DateUtils.SECOND_IN_MILLIS);
}
}
总结
- 应用发出Intent,要求应用内安装APK;
- PackageInstaller APP 中的
InstallStart
Activity接收到Intent,解析数据; - 转到PackageInstallerActivity展示界面,用户确认之后开始进入安装过程;
- 请求PackageManagerService去完成安装,这里会复制APK到指定目录中,并进行签名验证
- 通过binder机制请求
installd
守护进程去完成安装过程.