科技公司企业网站建设,网页设计学校官网代码,惠州微网站建设,金华网站制作企业上一篇内容说到InitAppsHelper这个类的initSystemApps函数#xff0c;只说了一下几个重要参数的来源还没展开#xff0c;这里继续#xff0c;有兴趣的可以看链接: Android 启动时应用的安装解析过程《一》
一、系统应用的扫描安装 /*** Install apps from system dirs.*/Gu…上一篇内容说到InitAppsHelper这个类的initSystemApps函数只说了一下几个重要参数的来源还没展开这里继续有兴趣的可以看链接: Android 启动时应用的安装解析过程《一》
一、系统应用的扫描安装 /*** Install apps from system dirs.*/GuardedBy({mPm.mInstallLock, mPm.mLock})public OverlayConfig initSystemApps(PackageParser2 packageParser,WatchedArrayMapString, PackageSetting packageSettings,int[] userIds, long startTime) {// Prepare apex package info before scanning APKs, this information is needed when// scanning apk in apex.// 扫描系统中apex信息为扫描APK做准备apex是系统中一种新的模块化组件final ListApexManager.ScanResult apexScanResults scanApexPackagesTraced(packageParser);mApexManager.notifyScanResult(apexScanResults);// 扫描系统目录中的apkscanSystemDirs(packageParser, mExecutorService);// Parse overlay configuration files to set default enable state, mutability, and// priority of system overlays.final ArrayMapString, File apkInApexPreInstalledPaths new ArrayMap();for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {final String apexPackageName mApexManager.getActivePackageNameForApexModuleName(apexInfo.apexModuleName);for (String packageName : mApexManager.getApksInApex(apexPackageName)) {apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);}}// 解析系统目录的overlay并把它使能final OverlayConfig overlayConfig OverlayConfig.initializeSystemInstance(consumer - mPm.forEachPackageState(mPm.snapshotComputer(),packageState - {var pkg packageState.getPkg();if (pkg ! null) {consumer.accept(pkg, packageState.isSystem(),apkInApexPreInstalledPaths.get(pkg.getPackageName()));}}));// do this first before mucking with mPackages for the expecting better case// 做一些优化比如禁用一些需要禁用的apk删除掉已经被删除的应用缓存updateStubSystemAppsList(mStubSystemApps);mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);logSystemAppsScanningTime(startTime);return overlayConfig;}1.扫描系统目录
private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {File frameworkDir new File(Environment.getRootDirectory(), framework);// Collect vendor/product/system_ext overlay packages. (Do this before scanning// any apps.)// For security and version matching reason, only consider overlay packages if they// reside in the right directory.for (int i mDirsToScanAsSystem.size() - 1; i 0; i--) {final ScanPartition partition mDirsToScanAsSystem.get(i);if (partition.getOverlayFolder() null) {continue;}// 扫描系统分区的overlay 文件夹scanDirTracedLI(partition.getOverlayFolder(),mSystemParseFlags, mSystemScanFlags | partition.scanFlag,packageParser, executorService, partition.apexInfo);}// 扫描system/framework文件夹scanDirTracedLI(frameworkDir,mSystemParseFlags, mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,packageParser, executorService, null);if (!mPm.mPackages.containsKey(android)) {throw new IllegalStateException(Failed to load frameworks package; check log for warnings);}for (int i 0, size mDirsToScanAsSystem.size(); i size; i) {final ScanPartition partition mDirsToScanAsSystem.get(i);if (partition.getPrivAppFolder() ! null) {// 扫描系统分区的priv-app文件夹scanDirTracedLI(partition.getPrivAppFolder(),mSystemParseFlags,mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,packageParser, executorService, partition.apexInfo);}// 扫描系统分区的app文件夹scanDirTracedLI(partition.getAppFolder(),mSystemParseFlags, mSystemScanFlags | partition.scanFlag,packageParser, executorService, partition.apexInfo);}}上面可以看到这个函数里面将系统分区的overlayapp还有jar包都扫描了个遍然后我们看下到底这个scanDirTracedLI函数里面做了哪些事情
private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,PackageParser2 packageParser, ExecutorService executorService,Nullable ApexManager.ActiveApexInfo apexInfo) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, scanDir [ scanDir.getAbsolutePath() ]);try {if ((scanFlags SCAN_AS_APK_IN_APEX) ! 0) {// when scanning apk in apexes, we want to check the maxSdkVersionparseFlags | PARSE_APK_IN_APEX;}// 调用到了InstallPackageHelper的installPackagesFromDirmInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags,scanFlags, packageParser, executorService, apexInfo);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}
}
InstallPackageHelper
public void installPackagesFromDir(File scanDir, int parseFlags,int scanFlags, PackageParser2 packageParser, ExecutorService executorService,Nullable ApexManager.ActiveApexInfo apexInfo) {//首先将所有的文件列出来final File[] files scanDir.listFiles();if (ArrayUtils.isEmpty(files)) {Log.d(TAG, No files in app dir scanDir);return;}if (DEBUG_PACKAGE_SCANNING) {Log.d(TAG, Scanning app dir scanDir scanFlags scanFlags flags0x Integer.toHexString(parseFlags));}// 这个又是个专门解析包的类ParallelPackageParser parallelPackageParser new ParallelPackageParser(packageParser, executorService);// Submit files for parsing in parallelint fileCount 0;for (File file : files) {// 这里判断是不是包是apk文件或者是文件夹并且不是stageName这个stageName是指// vmdl*.tmp,smdl*.tmp,smdl2tmp这些类的文件final boolean isPackage (isApkFile(file) || file.isDirectory()) !PackageInstallerService.isStageName(file.getName());if (!isPackage) {// Ignore entries which are not packagescontinue;}// 这里如果携带了SCAN_DROP_CACHE的flag会清除缓存if ((scanFlags SCAN_DROP_CACHE) ! 0) {final PackageCacher cacher new PackageCacher(mPm.getCacheDir(),mPm.mPackageParserCallback);Log.w(TAG, Dropping cache of file.getAbsolutePath());cacher.cleanCachedResult(file);}// 这里提交给解析器解析parallelPackageParser.submit(file, parseFlags);fileCount;}// Process results one by onefor (; fileCount 0; fileCount--) {ParallelPackageParser.ParseResult parseResult parallelPackageParser.take();Throwable throwable parseResult.throwable;int errorCode PackageManager.INSTALL_SUCCEEDED;String errorMsg null;// 如果没有异常就表示解析成功另外两个条件属于失败了if (throwable null) {try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, addForInitLI);// 这里初始化addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,new UserHandle(UserHandle.USER_SYSTEM), apexInfo);} catch (PackageManagerException e) {errorCode e.error;errorMsg Failed to scan parseResult.scanFile : e.getMessage();Slog.w(TAG, errorMsg);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}} else if (throwable instanceof PackageManagerException) {PackageManagerException e (PackageManagerException) throwable;errorCode e.error;errorMsg Failed to parse parseResult.scanFile : e.getMessage();Slog.w(TAG, errorMsg);} else {throw new IllegalStateException(Unexpected exception occurred while parsing parseResult.scanFile, throwable);}// apex的安装单独报给ApexManagerif ((scanFlags SCAN_AS_APK_IN_APEX) ! 0 errorCode ! INSTALL_SUCCEEDED) {mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);}// Delete invalid userdata apps// 没安装成功的会在这里清除if ((scanFlags SCAN_AS_SYSTEM) 0 errorCode ! PackageManager.INSTALL_SUCCEEDED) {logCriticalInfo(Log.WARN,Deleting invalid package at parseResult.scanFile);mRemovePackageHelper.removeCodePath(parseResult.scanFile);}}
}从上面可以看出主要就做了两件事情把文件夹下面的包一一解析并做初始化看看如何解析的先 ParallelPackageParser submit之后
2.开始解析
/*---------------------------ParallelPackageParser start ---------------------------*/
public void submit(File scanFile, int parseFlags) {// 直接开线程开始解析mExecutorService.submit(() - {ParseResult pr new ParseResult();Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, parallel parsePackage [ scanFile ]);try {pr.scanFile scanFile;// 解析pr.parsedPackage parsePackage(scanFile, parseFlags);} catch (Throwable e) {pr.throwable e;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}try {mQueue.put(pr);} catch (InterruptedException e) {Thread.currentThread().interrupt();// Propagate result to callers of take().// This is helpful to prevent main thread from getting stuck waiting on// ParallelPackageParser to finish in case of interruptionmInterruptedInThread Thread.currentThread().getName();}});
}protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageManagerException {try {// 发现这里又交给PackageParser2去做了return mPackageParser.parsePackage(scanFile, parseFlags, true);} catch (PackageParserException e) {throw new PackageManagerException(e.error, e.getMessage(), e);}
}
/*---------------------------ParallelPackageParser end---------------------------*/
/*---------------------------PackageParser2 start---------------------------*/
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {// 列出所有的文件var files packageFile.listFiles();// Apk directory is directly nested under the current directoryif (ArrayUtils.size(files) 1 files[0].isDirectory()) {packageFile files[0];}if (useCaches mCacher ! null) {// 这里会去检查有没有缓存缓存是存在data/system/目录下如果有缓存则不再解析ParsedPackage parsed mCacher.getCachedResult(packageFile, flags);if (parsed ! null) {return parsed;}}long parseTime LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;ParseInput input mSharedResult.get().reset();// 这里又交给了ParsingPackageUtils这个类去干活了ParseResultParsingPackage result mParsingUtils.parsePackage(input, packageFile, flags);if (result.isError()) {throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),result.getException());}ParsedPackage parsed (ParsedPackage) result.getResult().hideAsParsed();long cacheTime LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;// 这里解析好的结果保存到缓存也就是只要APK被解析过一次就会存在缓存了if (mCacher ! null) {mCacher.cacheResult(packageFile, flags, parsed);}if (LOG_PARSE_TIMINGS) {parseTime cacheTime - parseTime;cacheTime SystemClock.uptimeMillis() - cacheTime;if (parseTime cacheTime LOG_PARSE_TIMINGS_THRESHOLD_MS) {Slog.i(TAG, Parse times for packageFile : parse parseTime ms, update_cache cacheTime ms);}}return parsed;
}/*---------------------------PackageParser2 end---------------------------*/
/*---------------------------ParsingPackageUtils start---------------------------*/
public ParseResultParsingPackage parsePackage(ParseInput input, File packageFile, int flags) {// 如果是文件夹则走if 文件则走else这里为什么会这样分那/system/app目录来说// 系统在预置APP的时候可能是先在该目录下新建一层目录再放APK也有可能直接放置一个APK在该目录下if (packageFile.isDirectory()) {return parseClusterPackage(input, packageFile, flags);} else {return parseMonolithicPackage(input, packageFile, flags);}
}// 先看下解析目录parseClusterPackage
private ParseResultParsingPackage parseClusterPackage(ParseInput input, File packageDir,int flags) {int liteParseFlags 0;// 这里判断是不是在解析APEX的时候解析APKif ((flags PARSE_APK_IN_APEX) ! 0) {liteParseFlags | PARSE_APK_IN_APEX;}// 轻量解析APK这里会解析APK的签名信息AndroidManifest.xml中除了ActivityServiceContentProvider及权限以外的信息// 顺便会做一些校验比如SDK版本签名校验系统目录的APK 可以跳过签名校验签名校验从v4到v1逐一校验这一部分设计是为了节省时间final ParseResultPackageLite liteResult ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags);// 没有错误说明各种校验通过了if (liteResult.isError()) {return input.error(liteResult);}final PackageLite lite liteResult.getResult();// Build the split dependency tree.SparseArrayint[] splitDependencies null;final SplitAssetLoader assetLoader;// 如果是APKS 格式的这里会创建资源依赖树if (lite.isIsolatedSplits() !ArrayUtils.isEmpty(lite.getSplitNames())) {try {splitDependencies SplitAssetDependencyLoader.createDependenciesFromPackage(lite);assetLoader new SplitAssetDependencyLoader(lite, splitDependencies, flags);} catch (SplitAssetDependencyLoader.IllegalDependencyException e) {return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());}} else {assetLoader new DefaultSplitAssetLoader(lite, flags);}try {final File baseApk new File(lite.getBaseApkPath());boolean shouldSkipComponents lite.isIsSdkLibrary() disallowSdkLibsToBeApps();// 这里解析APKfinal ParseResultParsingPackage result parseBaseApk(input, baseApk,lite.getPath(), assetLoader, flags, shouldSkipComponents);if (result.isError()) {return input.error(result);}ParsingPackage pkg result.getResult();// 如果是APKS格式进行另外的解析if (!ArrayUtils.isEmpty(lite.getSplitNames())) {pkg.asSplit(lite.getSplitNames(),lite.getSplitApkPaths(),lite.getSplitRevisionCodes(),splitDependencies);final int num lite.getSplitNames().length;for (int i 0; i num; i) {final AssetManager splitAssets assetLoader.getSplitAssetManager(i);final ParseResultParsingPackage split parseSplitApk(input, pkg, i, splitAssets, flags);if (split.isError()) {return input.error(split);}}}pkg.set32BitAbiPreferred(lite.isUse32bitAbi());return input.success(pkg);} catch (IllegalArgumentException e) {return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK: INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);} finally {IoUtils.closeQuietly(assetLoader);}
}
/*******parseBaseApk******/private ParseResultParsingPackage parseBaseApk(ParseInput input, File apkFile,String codePath, SplitAssetLoader assetLoader, int flags,boolean shouldSkipComponents) {......// 又开始解析AndroidManifest.xmltry (XmlResourceParser parser assets.openXmlResourceParser(cookie,ANDROID_MANIFEST_FILENAME)) {final Resources res new Resources(assets, mDisplayMetrics, null);// 这里又一个重载解析APKParseResultParsingPackage result parseBaseApk(input, apkPath, codePath, res,parser, flags, shouldSkipComponents);if (result.isError()) {return input.error(result.getErrorCode(),apkPath (at parser.getPositionDescription() ): result.getErrorMessage());}final ParsingPackage pkg result.getResult();if (assets.containsAllocatedTable()) {final ParseResult? deferResult input.deferError(Targeting R (version Build.VERSION_CODES.R and above) requires the resources.arsc of installed APKs to be stored uncompressed and aligned on a 4-byte boundary,DeferredError.RESOURCES_ARSC_COMPRESSED);if (deferResult.isError()) {return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,deferResult.getErrorMessage());}}ApkAssets apkAssets assetLoader.getBaseApkAssets();boolean definesOverlayable false;try {// 查询该应用是否支持overlay,一般定义了相应的overlayabledefinesOverlayable apkAssets.definesOverlayable();} catch (IOException ignored) {// Will fail if theres no packages in the ApkAssets, which can be treated as false}// 如果可以这里会查找到可以被overlay的域if (definesOverlayable) {SparseArrayString packageNames assets.getAssignedPackageIdentifiers();int size packageNames.size();for (int index 0; index size; index) {String packageName packageNames.valueAt(index);MapString, String overlayableToActor assets.getOverlayableMap(packageName);if (overlayableToActor ! null !overlayableToActor.isEmpty()) {for (String overlayable : overlayableToActor.keySet()) {pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));}}}}pkg.setVolumeUuid(volumeUuid);// 这里又是查询验证签名信息if ((flags PARSE_COLLECT_CERTIFICATES) ! 0) {final ParseResultSigningDetails ret getSigningDetails(input, pkg, false /*skipVerify*/);if (ret.isError()) {return input.error(ret);}pkg.setSigningDetails(ret.getResult());} else {pkg.setSigningDetails(SigningDetails.UNKNOWN);}if (Flags.aslInApkAppMetadataSource()) {try (InputStream in assets.open(APP_METADATA_FILE_NAME)) {pkg.setAppMetadataFileInApk(true);} catch (Exception e) { }}return input.success(pkg);} catch (Exception e) {return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,Failed to read manifest from apkPath, e);}}/*******parseBaseApk 重载******/
private ParseResultParsingPackage parseBaseApk(ParseInput input, String apkPath,String codePath, Resources res, XmlResourceParser parser, int flags,boolean shouldSkipComponents)throws XmlPullParserException, IOException {final String splitName;final String pkgName;// 轻量解析包名信息之类的ParseResultPairString, String packageSplitResult ApkLiteParseUtils.parsePackageSplitNames(input, parser);if (packageSplitResult.isError()) {return input.error(packageSplitResult);}PairString, String packageSplit packageSplitResult.getResult();pkgName packageSplit.first;splitName packageSplit.second;if (!TextUtils.isEmpty(splitName)) {return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,Expected base APK, but found split splitName);}final TypedArray manifestArray res.obtainAttributes(parser, R.styleable.AndroidManifest);try {// 是否是core app 类似系统设置final boolean isCoreApp parser.getAttributeBooleanValue(null /*namespace*/,coreApp, false);final ParsingPackage pkg mCallback.startParsingPackage(pkgName, apkPath, codePath, manifestArray, isCoreApp);// 解析AndroidManinfest里面的各个TAG真正解析的开始final ParseResultParsingPackage result parseBaseApkTags(input, pkg, manifestArray, res, parser, flags,shouldSkipComponents);if (result.isError()) {return result;}return input.success(pkg);} finally {manifestArray.recycle();}}/**** parseBaseApkTags ****/
private ParseResultParsingPackage parseBaseApkTags(ParseInput input, ParsingPackage pkg,TypedArray sa, Resources res, XmlResourceParser parser, int flags,boolean shouldSkipComponents) throws XmlPullParserException, IOException {// 解析共享uidParseResultParsingPackage sharedUserResult parseSharedUser(input, pkg, sa);if (sharedUserResult.isError()) {return sharedUserResult;}// 用于标记系统为可更新通常和动态系统分区及增量更新机制有关。final boolean updatableSystem parser.getAttributeBooleanValue(null /*namespace*/,updatableSystem, true);// 用于设备恢复模式下的紧急安装或恢复。final String emergencyInstaller parser.getAttributeValue(null /*namespace*/,emergencyInstaller);pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,R.styleable.AndroidManifest_installLocation, sa)).setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,R.styleable.AndroidManifest_targetSandboxVersion, sa))/* Set the global on SD card flag */.setExternalStorage((flags PARSE_EXTERNAL_STORAGE) ! 0).setUpdatableSystem(updatableSystem).setEmergencyInstaller(emergencyInstaller);boolean foundApp false;final int depth parser.getDepth();int type;while ((type parser.next()) ! XmlPullParser.END_DOCUMENT (type ! XmlPullParser.END_TAG|| parser.getDepth() depth)) {if (type ! XmlPullParser.START_TAG) {continue;}if (sAconfigFlags.skipCurrentElement(parser)) {continue;}String tagName parser.getName();final ParseResult result;// application has special logic, so its handled outside the general method// 解析Application TAG配置及四大组件信息if (TAG_APPLICATION.equals(tagName)) {if (foundApp) {if (RIGID_PARSER) {result input.error(manifest has more than one application);} else {Slog.w(TAG, manifest has more than one application);result input.success(null);}} else {foundApp true;result parseBaseApplication(input, pkg, res, parser, flags,shouldSkipComponents);}} else {// Application 以外的TAG信息result parseBaseApkTag(tagName, input, pkg, res, parser, flags);}if (result.isError()) {return input.error(result);}}if (!foundApp ArrayUtils.size(pkg.getInstrumentations()) 0) {ParseResult? deferResult input.deferError(manifest does not contain an application or instrumentation,DeferredError.MISSING_APP_TAG);if (deferResult.isError()) {return input.error(deferResult);}}return validateBaseApkTags(input, pkg, flags);}后面都是一些解析细节了不在追述值得注意的是大部分APK 只会解析一次会将APK 的信息存储在/data/system/package_caches下面除非apk出现了更新否则不会再重新解析