type
status
date
slug
summary
tags
category
icon
password
Android系统的代码总是在不断迭代的,具体的类和方法本身并不重要,关键是了解流程与主要的路径
本文基于AOSP master分支 2020年8月,Android 11 已经处于beta版

三种安装方式

  • 系统级app安装
  • 普通app安装
  • adb安装
这里看一下普通APP的安装.
在分析之前,想一下如果是我们来安装apk,需要怎么做:
  1. apk实际上是一个zip包,先解压,要不然只能测量下大小了,当然也可以不解压直接查看zip包的内容
  1. 系统重启之后我们依然要快速显示和启动app,那么肯定得存一份APP信息到手机上,那么存什么信息呢?
      • 可执行文件的位置,在Android里跑的是dex,或者dex处理过后的机器码,因此这里应该是dex或者oat文件的位置
      • 应用有一些特殊的功能,比如可以用来打开文档,网页等,因此需要把这些信息注册到一个系统表里,可以快速查询,Android中应也有这么一个表
      而且最好是把apk的资源,可执行文件等内部数据放到一个文件夹下,这样卸载的时候可以直接删除目录.
  1. zip包解压了,信息也存了,为了安全,应该把对应的可执行文件和资源文件复制到指定的路径,如果有so库,还要让程序知道去哪里找so文件
  1. 检查手机上之前是否已经安装了这个app,如果安装了,比较一下版本,签名,再确定怎么处理
  1. 删除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,然后就是不同的安装进度了,InstallInstallingInstallFailedInstallSuccess:
来看一下关键的对象:
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个步骤:
  1. prepare
    1. 使用PackageParser解析APK,获取各种信息,检查是否有静态共享库,有的话放在内部存储中.决定安装方式(更新,还是新安装)之类的逻辑.
  1. scan
    1. 扫描APK,更新共享库和Settings信息
  1. reconcile
    1. 新旧包以及签名相关的逻辑
  1. commit
    1. 更新设置
其实都是对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); } }
这里主要分为两部:
  1. 调用Installer创建APP数据
  1. 如果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); } }

总结

  1. 应用发出Intent,要求应用内安装APK;
  1. PackageInstaller APP 中的InstallStartActivity接收到Intent,解析数据;
  1. 转到PackageInstallerActivity展示界面,用户确认之后开始进入安装过程;
  1. 请求PackageManagerService去完成安装,这里会复制APK到指定目录中,并进行签名验证
  1. 通过binder机制请求installd守护进程去完成安装过程.
Android APP启动流程分析AOSP构建-Android.bp的理解
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏