调试应用,一般两种方式把apk通过adb push到指定目录或者通过adb install 。
做系统应用开发一般使用adb push到 指定目录进行调试,然后kill进程,等待应用再被拉起,但是会遇到一个问题,把APK通过adb push到设备后重启之前AndroidManifest.xml的修改不生效。
为什么会出现这个现象,就需要了解AndroidManifest.xml啥时候被加载的。
APK的安装,离不开PMS (PackageManagerService)
先上图
解析AndroidManifest流程.png
首先分析PMS的启动
PMS (PackageManagerService)启动过程
- SystemServer --> main() --> startBootstrapServices() --> PackageManagerService.main()
/**
* The main entry point from zygote.<--源头
*/
public static void main(String[] args) {
new SystemServer().run();
}
....
....
private void run() {
...
...
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
startApexServices(t);
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
}
...
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
...
...
//启动installer服务,从名字可以看出此服务与安装apk相关,里面主要是管理apk的各种信息,AMS和PMS启动时都需要这个参数
t.traceBegin("StartInstaller");
Installer installer = mSystemServiceManager.startService(Installer.class);
t.traceEnd();
//这里是启动AMS
// Activity manager runs the show.
t.traceBegin("StartActivityManager");
//这里有备注可能以后会换地方
// TODO: Might need to move after migration to WM.
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mWindowManagerGlobalLock = atm.getGlobalLock();
t.traceEnd();
...
...
// Only run "core" apps if we're encrypting the device.
//启动min-framework 显示密码输入界面,仅启动 coreApp, 在AndroidManifest.xml中声明。
//此时启动的 APP 在 tmpfs 临时分区,所以,所有app都是原始安装状态,不包含任何用户使用产生的数据。
String cryptState = VoldProperties.decrypt().orElse("");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
....
....
t.traceBegin("StartDomainVerificationService");
//这个服务作为参数传进PMS,主要是为了做一些校验工作
DomainVerificationService domainVerificationService = new DomainVerificationService(
mSystemContext, SystemConfig.getInstance(), platformCompat);
mSystemServiceManager.startService(domainVerificationService);
t.traceEnd();
...
...
//启动PMS
t.traceBegin("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
Pair<PackageManagerService, IPackageManager> pmsPair = PackageManagerService.main(
mSystemContext, installer, domainVerificationService,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mPackageManagerService = pmsPair.first;
iPackageManager = pmsPair.second;
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
...
...
}
......
.....
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
...
WindowManagerService wm = null;
...
...
//启动WMS
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
t.traceBegin("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm);
t.traceEnd();
t.traceBegin("WindowManagerServiceOnInitReady");
wm.onInitReady();
t.traceEnd();
.....
.....
}
注意此处开始Android的10到13版本各有变化,其中11到13属于重构逐渐迭代过程
Android T(13) SDK32版本的过程以后分析
PackageManagerService --> main()
Android Q(10) SDK29版本的过程
-
PackageManagerService -> main() --> new PackageManagerService()
在这个巨大无比的构造方法中摘出我们需要关心的两个方法
-->scanDirTracedLI()
-->installSystemStubPackages()
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
....
....
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_VENDOR,
0);
/**省略了很多目录 PRODUCT_OVERLAY_DIR,PRODUCT_SERVICES_OVERLAY_DIR 等等*/
....
....
// Find base frameworks (resource packages without code).
//扫描安装“system\framework”目录下的jar包
scanDirTracedLI(frameworkDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_NO_DEX
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED,
0);
....
....
// Collect privileged system packages. /system/priv-app
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirTracedLI(privilegedAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM
| SCAN_AS_PRIVILEGED,
0);
/**省略了很多目录 Environment.getRootDirectory()+"app" == /system/app,
Environment.getVendorDirectory()+"priv-app"== /vendor/piv-app
Environment.getVendorDirectory()+"app"== /vendor/app
Environment.getOdmDirectory()+"priv-app"== /omd/piv-app
Environment.getOdmDirectory()+"app"== /omd/app
Environment.getOemDirectory()+"app"== /oed/piv-app
Environment.getProductDirectory()+"priv-app"== /product/piv-app
Environment.getProductDirectory()+"app"== /product/app
Environment.getProductServicesDirectory()+"priv-app"== //product_services/priv-app
Environment.getProductServicesDirectory()+"app"== //product_services/app **/
....
....
// Stub packages must either be replaced with full versions in the /data
// partition or be disabled.
final List<String> stubSystemApps = new ArrayList<>();
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
//mPackages是在方法scanDirTracedLI中赋值的
final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
while (pkgIterator.hasNext()) {
final PackageParser.Package pkg = pkgIterator.next();
if (pkg.isStub) {
stubSystemApps.add(pkg.packageName);
}
}
....
....
}
....
....
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
//sAppInstallDir这个目录是 Environment.getDataDirectory()+ "app" == /data/app
//扫描三方安装目录
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
....
....
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
//安装系统应用
installSystemStubPackages(stubSystemApps, scanFlags);
}
....
....
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
//更新所有应用库的路径
updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));
....
...
for (String pkgName : deferPackages) {
....
//最后会调到 mInstaller.createAppData,
//通过Binder调用到 进程installd,最终调用installd的createAppData()
prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */);
....
}
}
方法scanDirTracedLI()
--> scanDirLI()此方法中又有两个值得关注的方法
-->parallelPackageParser.submit(file, parseFlags)
-->scanPackageChildLI()
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
....
....
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
//解析apk文件,主要是对AndroidManifest.xml进行解析,解析后所有的信息放在Package对象中
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
for (; fileCount > 0; fileCount--) {
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
....
....
scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,currentTime, null);
....
}
}
....
}
-
首先看parallelPackageParser.submit方法
ParallelPackageParser --> parallelPackageParser.submit(file, parseFlags) --> parsePackage()
/**
* Submits the file for parsing
* @param scanFile file to scan
* @param parseFlags parse falgs
*/
public void submit(File scanFile, int parseFlags) {
mService.submit(() -> {
ParseResult pr = new ParseResult();
...
try {
....
....
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
mQueue.put(pr);
} catch (InterruptedException e) {
....
}
});
}
@VisibleForTesting
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}
继续跟进,这个过程中注意是对apk资源的加载和AndroidManifest.xml的解析
PackageParser -> parsePackage() 其中两个方法最终都会调用到 parseBaseApk()
-->parseBaseApk()-->parseBaseApkCommon() 中包括解析四大组件,权限等等方法
-->parseBaseApplication() 具体往里跟进一下
--->parsePermission()
....
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
//因为AndroidManifest.xml 文件解析节点很多很庞大,这一步是对其进行一个初步解析,
//获取应用目录的PackageLite对象,这个对象分开保存了目录下的核心应用以及非核心应用
//主要用于对apk资源的加载
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
....
....
//对apk资源的加载
final AssetManager assets = assetLoader.getBaseAssetManager();
....
//对核心应用解析 parseBaseApk
final Package pkg = parseBaseApk(baseApk, assets, flags);
....
....
for (int i = 0; i < num; i++) {
//对非核心apk资源的加载
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
//对非核心应用的处理
parseSplitApk(pkg, i, splitAssets, flags);
}
}
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
//对AndroidManifest.xml 文件进行初步解析,主要用于对apk资源的加载
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
....
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
....
//对核心应用解析 ,assetLoader.getBaseAssetManager()是对apk资源的加载
final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
}
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
....
....
//获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件。
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
//再调用重载函数parseBaseApk()最终到parseBaseApkCommon(),解析AndroidManifest.xml 后得到一个Package对象
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
....
....
}
private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
....
....
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
.....
....
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
//从AndroidManifest.xml中获取标签名
String tagName = parser.getName();
....
//如果读到AndroidManifest.xml中的tag是"application",执行parseBaseApplication()进行解析
if (tagName.equals(TAG_APPLICATION)) {
....
....
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
return null;
}
}
.....
.....
// //如果标签是"permission"
else if (tagName.equals(TAG_PERMISSION)) {
if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
}
}
.....
....
}
//在该方法中可以看出四大组件的解析过程
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
....
....
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
....
}
....
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
.....
....
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
.....
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
.....
}
}
-
在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象,下一步就是将该 Package 加入到系统中,接下来是方法scanPackageChildLI()
scanPackageChildLI() --> addForInitLI()
主要进行安装包校验、签名检查、apk更新等操作
/**
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
@GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user){
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
scanFlags |= SCAN_CHECK_ONLY;
}
} else {
scanFlags &= ~SCAN_CHECK_ONLY;
}
//在addForInitLI()中,进行安装包校验、签名检查、apk更新等操作,把Package加入系统
// Scan the parent
PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
scanFlags, currentTime, user);
// Scan the children
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;
}
以上是scanDirTracedLI()方法的流程,简单总结一下就是扫描系统存放apk目录解析AndroidManifest.xml文件生成Package,然后进行校验、签名检查、apk更新等操作,把Package加入系统;
接下来是方法 installSystemStubPackages(),
主要功能是对压缩编译后的apk.gz进行解压安装,为了优化system分区空间,对app进行压缩编译
installSystemStubPackages()--> installStubPackageLI(pkg, 0, scanFlags) 中有两个关键方法
-->decompressPackage()
-->scanPackageTracedLI()
private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
@ScanFlags int scanFlags) {
....
....
installStubPackageLI(pkg, 0, scanFlags);
}
private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags)
throws PackageManagerException {
....
// uncompress the binary to its eventual destination on /data
//解压到data目录
final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
...
...
try {
return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
}
....
}
- 首先看方法decompressPackage() --> PackageManagerServiceUtils -->decompressFile()
private File decompressPackage(String packageName, String codePath) {
//过滤是否有压缩编译的,gz文件
final File[] compressedFiles = getCompressedFiles(codePath);
if (compressedFiles == null || compressedFiles.length == 0) {
.....
return null;
}
//这个Environment.getDataAppDirectory是/data/app目录,也就是说解压安装压缩编译后的路径是和通过install安装的分区目录是一样的
final File dstCodePath =
getNextCodePath(Environment.getDataAppDirectory(null), packageName);
int ret = PackageManager.INSTALL_SUCCEEDED;
try {
Os.mkdir(dstCodePath.getAbsolutePath(), 0755);
Os.chmod(dstCodePath.getAbsolutePath(), 0755);
for (File srcFile : compressedFiles) {
final String srcFileName = srcFile.getName();
final String dstFileName = srcFileName.substring(
0, srcFileName.length() - COMPRESSED_EXTENSION.length());
final File dstFile = new File(dstCodePath, dstFileName);
ret = decompressFile(srcFile, dstFile);
.....
}
}
.....
.....
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(dstCodePath);
//释放apk中的so文件到本地目录
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
null /*abiOverride*/);
}
.....
}
....
return dstCodePath;
}
PackageManagerServiceUtils -->decompressFile()
解压压缩文件
public static int decompressFile(File srcFile, File dstFile) throws ErrnoException {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Decompress file"
+ "; src: " + srcFile.getAbsolutePath()
+ ", dst: " + dstFile.getAbsolutePath());
}
try (
InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
) {
FileUtils.copy(fileIn, fileOut);
Os.chmod(dstFile.getAbsolutePath(), 0644);
return PackageManager.INSTALL_SUCCEEDED;
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress file"
+ "; src: " + srcFile.getAbsolutePath()
+ ", dst: " + dstFile.getAbsolutePath());
}
return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
- 再看installStubPackageLI() --> scanPackageTracedLI()--> scanPackageLI()
接下来跟上面分析的扫描系统指定目录对apk的处理是一样的
-->PackageParser-->pp.parsePackage()先解析
-->scanPackageChildLI()再进行校验、签名检查、apk更新等操作,把Package加入系统;
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
.....
return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
.....
}
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
....
PackageParser pp = new PackageParser();
....
pkg = pp.parsePackage(scanFile, parseFlags);
....
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
到这里已经我们已经分析到了系统应用AndroidManifest.xml被解析过程,这些都是再PMS的构造方法中执行的,而PMS是再SystemServer中被启动的,所以想要在系统目录下/system、//vendor等等目录下的apk的AndroidManifest.xml生效,需要重启系统,或者重启SystemServer进程。
另外关于系统应用安装?
安装的原理就是把通过进程间通信通过PMS完成对apk复制到指定目录/data/app、/system/app、/system/priv-app等,对齐进行解析,的操作,系统应用本身就在指定目录,所以在PMS启动后完成解析就是安装完成了
网友评论