android 5.0后对于apk 跑32 64 的逻辑
来源:互联网 发布:优米网域名交易 编辑:程序博客网 时间:2024/06/05 05:05
1, 是否是 64 bit apk,在对应的 full_sky828_8s70.mk 里面,这里主要包含64 bit apk的支持, 还有zygote的启动方式,64 bit apk fork的简要过程
Inherit from hardware-specific part of the product configuration.
$(call inherit-product, device/skyworth/sky828_8s70/device.mk)
Inherit from the common Open Source product configuration.
$(call inherit-product-if-exists, vendor/google/products/gms.mk)
这个里面主要的内容是:
Copy the 64-bit primary, 32-bit secondary zygote startup script
PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.rc:root/init.zygote64_32.rc
Set the zygote property to select the 64-bit primary, 32-bit secondary script
This line must be parsed before the one in core_minimal.mk
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote64_32
TARGET_SUPPORTS_32_BIT_APPS := true
TARGET_SUPPORTS_64_BIT_APPS := true
这里主要是表明编译系统support 32 , 64 apk, 还有把zygote 名字ro.zygote设置为 zygote64_32,
在L之前启动zygote 是直接在 init.rc 里面通过
service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
这个来启动的, 但L上由于可能有2个zygote, 所以把zygote的启动脚本抽象到一个单独的rc文件里面, 根据ro.zygote来区分。
这个单独的脚本是在init rc里面include的。 具体如下
import /init.environ.rc
import /init.usb.rc
import /init.
import /init.trace.rc
同时在 zygote64_32 脚本这个里面做了什么了?
service zygote /system/bin/app_process64 -Xzygote /system/bin –zygote –start-system-server –socket-name=zygote
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin –zygote –socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
这里启动了2个zygote, 其中一个是bin是 32bit的, 一个bin是64 bit的, 注意这里的socket的名字 , 一个是zygote, 一个是zygote_secondary,第一个是primary zygote。我们之前知道, 在启动apk的时候, 是从zygote出来的, 所以在L上, 启动一个process之前, 会判断是多少bit,然后向对应的zygote请求fork 子进程出来, 我们知道fork 子进程会集成父进程的属性, 所以子 进程的位数跟父进程一致,从而如果我们要看一个 apk是多少bit, 可以通过看父进程是32bit的zygote,还是 64 bit的zygote
下面我们看一下启动 process的时候, 是如何判断 apk的 指令集的, 最终start 一个app的process 都是call到activitymanagerservice里面去的,startProcessLocked
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;==》 这个值是在安装 apk的时候拿出来的,这里这个值对于按照正常规范写的有native code的apk, 这个值就是有值的,不是空, 但是对于没有nativelib的,比如是pure java 的apk, 这个就是null。
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
==》这里的意思是系统无法根据lib 来判断apk是多少bit的, 就会用系统support的 第一个 abi 来作为这个apk的 指令集, 这就是为什么在 系统上, 如果有pure java的 apk , 肯定会跑 64 bit,而不是32 bit。在以64 系统为主的 系统上,系统support的 abi 如下:
shell@sky828_8s70:/ # getprop ro.product.cpu.abilist
arm64-v8a,armeabi-v7a,armeabi
String instructionSet = null; if (app.info.primaryCpuAbi != null) { instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi); }
我说一下 这里 abi 跟 instructionset的关系, 对于64 为主, 也只是 32 bit 的系统, abi就是 arm64-v8a,armeabi-v7a,armeabi
,
那instructionset了, 其实 是根据 abi算过来的, arm64-v8a 对应的 指令集就是 arm64, 而 armeabi-v7a,armeabi 对应的就是 arm
然后才会开始真的startprocess,这里会传进入 abi, 跟 instructionset,
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = “android.app.ActivityThread”;
checkTime(startTime, “startProcess: asking zygote to start proc”);
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
在往后看, 会call到
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); 我们看 openZygoteSocketIfNeeded , 这个里面, 由此可以看出 判断apk 跑哪个进程,还是根据前面的 abi来的。
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx(“Error connecting to primary zygote”, ioe);
}
}
if (primaryZygoteState.matches(abi)) { return primaryZygoteState; } // The primary zygote didn't match. Try the secondary. if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { try { secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET); } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe); } } if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
这里的 primaryZygoteState 就是连接到名字叫zygote的 primary zygote, secondaryZygoteState 代表的是第二个,
这里首先会判断apk需要的abi是否在primary zygote支持的abi里面, 如果不在 才会去secondary zygote去看。最终会根据找到对应的。
那系统是如何判断primary zygote 支持哪些 abi的了?
Matches方法主要是
boolean matches(String abi) {
return abiList.contains(abi);
} 我们看 abilist是如何获得到 ,
public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
try { zygoteSocket.connect(new LocalSocketAddress(socketAddress, LocalSocketAddress.Namespace.RESERVED)); zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); zygoteWriter = new BufferedWriter(new OutputStreamWriter( zygoteSocket.getOutputStream()), 256); } catch (IOException ex) { try { zygoteSocket.close(); } catch (IOException ignore) { } throw ex; } String abiListString = getAbiList(zygoteWriter, zygoteInputStream); Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString); return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, Arrays.asList(abiListString.split(","))); }
然后getAbiList又是如何的了?
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
throws IOException {
// Each query starts with the argument count (1 in this case)
writer.write(“1”);
// … followed by a new-line.
writer.newLine();
// … followed by our only argument.
writer.write(“–query-abi-list”);
writer.newLine();
writer.flush();
// The response is a length prefixed stream of ASCII bytes. int numBytes = inputStream.readInt(); byte[] bytes = new byte[numBytes]; inputStream.readFully(bytes); return new String(bytes, StandardCharsets.US_ASCII);}
发现这个是还是通过socket 去查询结果的。 我们去看看server端的东西。
if defined(LP64)
static const char ABI_LIST_PROPERTY[] = “ro.product.cpu.abilist64”;
static const char ZYGOTE_NICE_NAME[] = “zygote64”;
else
static const char ABI_LIST_PROPERTY[] = “ro.product.cpu.abilist32”;
static const char ZYGOTE_NICE_NAME[] = “zygote”;
endif
在以 64 位为主的系统上,这两个属性的结果如下:
127|shell@sky828_8s70:/ # getprop ro.product.cpu.abilist64
arm64-v8a
shell@sky828_8s70:/ # getprop ro.product.cpu.abilist32
armeabi-v7a,armeabi
shell@sky828_8s70:/ #
在zygote 启动的main 函数里面, 会根据这两个属性获取到自己支持的abi
int main(int argc, char* const argv[])
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
// Older kernels don’t understand PR_SET_NO_NEW_PRIVS and return
// EINVAL. Don’t die on such kernels.
if (errno != EINVAL) {
LOG_ALWAYS_FATAL(“PR_SET_NO_NEW_PRIVS failed: %s”, strerror(errno));
return 12;
}
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv++;// Everything up to '--' or first non '-' arg goes to the vm.//// The first argument after the VM args is the "parent dir", which// is currently unused.//// After the parent dir, we expect one or more the following internal// arguments ://// --zygote : Start in zygote mode// --start-system-server : Start the system server.// --application : Start in application (stand alone, non zygote) mode.// --nice-name : The nice name for this process.//// For non zygote starts, these arguments will be followed by// the main class name. All remaining arguments are passed to// the main method of this class.//// For zygote starts, all remaining arguments are passed to the zygote.// main function.//// Note that we must copy argument string values since we will rewrite the// entire argument block when we apply the nice name to argv0.int i;for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i]));}// Parse runtime arguments. Stop at first unrecognized option.bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;++i; // Skip unused "parent dir" argument.while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; }}Vector<String8> args;if (!className.isEmpty()) { // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main(). Make // copies of them before we overwrite them with the process name. args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i);} else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); }}if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string());}if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args);} else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args);} else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10;}
}
Native里面最后通过 runtime.start(“com.android.internal.os.ZygoteInit”, args); call到 java层上面,也就是com.android.internal.os.ZygoteInit 这个类的main方法
在java里面就会把这里放到args里面的 指令集取出来,
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { socketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } registerZygoteSocket(socketName);
我们再客户端通过socket 请求对应的socket 拿到的 abi,其实就是这里拿出来的 指,
2,apk的安装过程, 主要是packagemanagerservice里面 判断 apk 跑多少bit的这段逻辑。
Pms 是在systemserver里面启动起来的,
// Start the package manager.
Slog.i(TAG, “Package Manager”);
mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();//这里的isFirstBoot 就是判断系统是否是第一次启动,恢复出厂设置, 然后再启动,也认为是第一次,为什么第一次启动 apk 做优化,没有转圈圈,就与这个有关系
try {
mPackageManagerService.performBootDexOpt();
} catch (Throwable e) {
reportWtf(“performing boot dexopt”, e);
}
try { ActivityManagerNative.getDefault().showBootMessage( context.getResources().getText( com.android.internal.R.string.android_upgrading_starting_apps), false); } catch (RemoteException e) { }
我们看一下scan system app下的大概过程
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), “app”);
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
注意下这里的scanFlags,是下面这个值, 主要注意第二个参数 SCAN_DEFER_DEX,这个表示是推迟dex动作, 也就是说在在扫描这个目录的时候,并不是扫描一个apk,就优化一个apk, 而是放到一个待优化列表,等扫描结束之后, 一起来做优化动作。
// Set flag to monitor and not change apk file paths when
// scanning install directories.
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
通过这个函数会call到下面这个function
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles(); 列出这个目录下的所有file,注意其实这里不是file,而是目录, 因为L上 apk的形式多了一级目录,eg/system/app/helloworld/helloworld.apk 是这种形式
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, “No files in app dir ” + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags + " flags=0x" + Integer.toHexString(parseFlags)); } 循环安装这个目录下的每个 apk for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } try { scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK, scanFlags, currentTime, null); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage()); // Delete invalid userdata apps if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 && e.error == PackageManager.INSTALL_FAILED_INVALID_APK) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + file); if (file.isDirectory()) { FileUtils.deleteContents(file); } file.delete(); } } }}
我们根据这个scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
在往下走,
* Scan a package and return the newly parsed package.
* Returns null in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, “Parsing: ” + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(); 主要用来解析apk里面AndroidManifest.xml 文件的
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) { parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY; } final PackageParser.Package pkg; try { pkg = pp.parsePackage(scanFile, parseFlags);真正开始解析 apk里面AndroidManifest.xml 文件的,这个过程请看后面的流程 parsePackage, 这里主要是解析mafifest文件, 把信息记录到package对象里面 } catch (PackageParserException e) { throw PackageManagerException.from(e); } PackageSetting ps = null; PackageSetting updatedPkg; // reader synchronized (mPackages) { // Look to see if we already know about this package. String oldName = mSettings.mRenamedPackages.get(pkg.packageName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) { // This package has been renamed to its original name. Let's // use that. ps = mSettings.peekPackageLPr(oldName); } // If there was no original package, see one for the real package name. if (ps == null) { ps = mSettings.peekPackageLPr(pkg.packageName); } // Check to see if this package could be hiding/updating a system // package. Must look for it either under the original or real // package name depending on our state. updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName); if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg); } boolean updatedPkgBetter = false; // First check if this is a system package that may involve an update if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { if (ps != null && !ps.codePath.equals(scanFile)) { // The path has changed from what was last scanned... check the // version of the new path against what we have stored to determine // what to do. if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath); if (pkg.mVersionCode < ps.versionCode) { // The system package has been updated and the code path does not match // Ignore entry. Skip it. logCriticalInfo(Log.INFO, "Package " + ps.name + " at " + scanFile + " ignored: updated version " + ps.versionCode + " better than this " + pkg.mVersionCode); if (!updatedPkg.codePath.equals(scanFile)) { Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : " + ps.name + " changing from " + updatedPkg.codePathString + " to " + scanFile); updatedPkg.codePath = scanFile; updatedPkg.codePathString = scanFile.toString(); // This is the point at which we know that the system-disk APK // for this package has moved during a reboot (e.g. due to an OTA), // so we need to reevaluate it for privilege policy. if (locationIsPrivileged(scanFile)) { updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED; } } updatedPkg.pkg = pkg; throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null); } else { // The current app on the system partition is better than // what we have updated to on the data partition; switch // back to the system partition version. // At this point, its safely assumed that package installation for // apps in system partition will go through. If not there won't be a working // version of the app // writer synchronized (mPackages) { // Just remove the loaded entries from package lists. mPackages.remove(ps.name); } logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile + " reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, getAppDexInstructionSets(ps)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } synchronized (mPackages) { mSettings.enableSystemPackageLPw(ps.name); } updatedPkgBetter = true; } } } if (updatedPkg != null) { // An updated system app will not have the PARSE_IS_SYSTEM flag set // initially parseFlags |= PackageParser.PARSE_IS_SYSTEM; // An updated privileged app will not have the PARSE_IS_PRIVILEGED // flag set initially if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { parseFlags |= PackageParser.PARSE_IS_PRIVILEGED; } } // Verify certificates against what was last scanned collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags); /* * A new system app appeared, but we already had a non-system one of the * same name installed earlier. */ boolean shouldHideSystemApp = false; if (updatedPkg == null && ps != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) { /* * Check to make sure the signatures match first. If they don't, * wipe the installed application and its data. */ if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but" + " signatures don't match existing userdata copy; removing"); deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false); ps = null; } else { /* * If the newly-added system app is an older version than the * already installed version, hide it. It will be scanned later * and re-added like an update. */ if (pkg.mVersionCode < ps.versionCode) { shouldHideSystemApp = true; logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile + " but new version " + pkg.mVersionCode + " better than installed " + ps.versionCode + "; hiding system"); } else { /* * The newly found system app is a newer version that the * one previously installed. Simply remove the * already-installed application and replace it with our own * while keeping the application data. */ logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile + " reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, getAppDexInstructionSets(ps)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } } } } // The apk is forward locked (not public) if its code and resources // are kept in different files. (except for app in either system or // vendor path). // TODO grab this value from PackageSettings if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { if (ps != null && !ps.codePath.equals(ps.resourcePath)) { parseFlags |= PackageParser.PARSE_FORWARD_LOCK; } } // TODO: extend to support forward-locked splits String resourcePath = null; String baseResourcePath = null; if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) { if (ps != null && ps.resourcePathString != null) { resourcePath = ps.resourcePathString; baseResourcePath = ps.resourcePathString; } else { // Should not happen at all. Just log an error. Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName); } } else { resourcePath = pkg.codePath; baseResourcePath = pkg.baseCodePath; } // Set application objects path explicitly. pkg.applicationInfo.setCodePath(pkg.codePath); pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath); pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths); pkg.applicationInfo.setResourcePath(resourcePath); pkg.applicationInfo.setBaseResourcePath(baseResourcePath); pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths); // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); /* * If the system app should be overridden by a previously installed * data, hide the system app now and let the /data/app scan pick it up * again. */ if (shouldHideSystemApp) { synchronized (mPackages) { /* * We have to grant systems permissions before we hide, because * grantPermissions will assume the package update is trying to * expand its permissions. */ grantPermissionsLPw(pkg, true, pkg.packageName); mSettings.disableSystemPackageLPw(pkg.packageName); } } return scannedPkg;}
#
parsePackage:
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
注意,我们这里是目录, 而不是文件, 所以会走return parseClusterPackage(packageFile, flags); 再往下走
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
if (mOnlyCoreApps && !lite.coreApp) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "Not a coreApp: " + packageDir); } final AssetManager assets = new AssetManager(); try { // Load the base and all splits into the AssetManager // so that resources can be overriden when parsing the manifests. loadApkIntoAssetManager(assets, lite.baseCodePath, flags); if (!ArrayUtils.isEmpty(lite.splitCodePaths)) { for (String path : lite.splitCodePaths) { loadApkIntoAssetManager(assets, path, flags); } } final File baseApk = new File(lite.baseCodePath); final Package pkg = parseBaseApk(baseApk, assets, flags); if (pkg == null) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Failed to parse base APK: " + baseApk); } if (!ArrayUtils.isEmpty(lite.splitNames)) { final int num = lite.splitNames.length; pkg.splitNames = lite.splitNames; pkg.splitCodePaths = lite.splitCodePaths; pkg.splitFlags = new int[num]; for (int i = 0; i < num; i++) { parseSplitApk(pkg, i, assets, flags); } } pkg.codePath = packageDir.getAbsolutePath(); return pkg; } finally { IoUtils.closeQuietly(assets); }}
这里主要看两个函数,一个是 parseClusterPackageLite, 一个是 parseBaseApk, 其中要明白两个class的含义, 其中packagelite是一个轻量级的package的信息, 主要只包含下面的信息
public static class PackageLite {
public final String packageName;
public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
/** Names of any split APKs, ordered by parsed splitName */ public final String[] splitNames; /** * Path where this package was found on disk. For monolithic packages * this is path to single base APK file; for cluster packages this is * path to the cluster directory. */ public final String codePath; /** Path of base APK */ public final String baseCodePath; /** Paths of any split APKs, ordered by parsed splitName */ public final String[] splitCodePaths; public final boolean coreApp; public final boolean multiArch;
但是Package 就是一个apk的详细信息, 比如这个apk 里面的activity,service,broadcast,contentprovider 列表, 内容比较多。我只贴一部分
public final static class Package {
public String packageName; /** Names of any split APKs, ordered by parsed splitName */ public String[] splitNames; // TODO: work towards making these paths invariant /** * Path where this package was found on disk. For monolithic packages * this is path to single base APK file; for cluster packages this is * path to the cluster directory. */ public String codePath; /** Path of base APK */ public String baseCodePath; /** Paths of any split APKs, ordered by parsed splitName */ public String[] splitCodePaths; /** Flags of any split APKs; ordered by parsed splitName */ public int[] splitFlags; public boolean baseHardwareAccelerated; // For now we only support one application per package. public final ApplicationInfo applicationInfo = new ApplicationInfo(); public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); public final ArrayList<Activity> activities = new ArrayList<Activity>(0); public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); public final ArrayList<Provider> providers = new ArrayList<Provider>(0); public final ArrayList<Service> services = new ArrayList<Service>(0); public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); public final ArrayList<String> requestedPermissions = new ArrayList<String>(); public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>(); public ArrayList<String> protectedBroadcasts;
然后来看函数 final PackageLite lite = parseClusterPackageLite(packageDir, 0);
private static PackageLite parseClusterPackageLite(File packageDir, int flags)
throws PackageParserException {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
“No packages found in split”);
}
String packageName = null; int versionCode = 0; final ArrayMap<String, ApkLite> apks = new ArrayMap<>(); for (File file : files) { if (isApkFile(file)) { final ApkLite lite = parseApkLite(file, flags); // Assert that all package names and version codes are // consistent with the first one we encounter. if (packageName == null) { packageName = lite.packageName; versionCode = lite.versionCode; } else { if (!packageName.equals(lite.packageName)) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Inconsistent package " + lite.packageName + " in " + file + "; expected " + packageName); } if (versionCode != lite.versionCode) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Inconsistent version " + lite.versionCode + " in " + file + "; expected " + versionCode); } } // Assert that each split is defined only once if (apks.put(lite.splitName, lite) != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Split name " + lite.splitName + " defined more than once; most recent was " + file); } } } final ApkLite baseApk = apks.remove(null); if (baseApk == null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, "Missing base APK in " + packageDir); } // Always apply deterministic ordering based on splitName final int size = apks.size(); String[] splitNames = null; String[] splitCodePaths = null; if (size > 0) { splitNames = new String[size]; splitCodePaths = new String[size]; splitNames = apks.keySet().toArray(splitNames); Arrays.sort(splitNames, sSplitNameComparator); for (int i = 0; i < size; i++) { splitCodePaths[i] = apks.get(splitNames[i]).codePath; } } final String codePath = packageDir.getAbsolutePath(); return new PackageLite(codePath, baseApk, splitNames, splitCodePaths);}
其中paseapklite 就是拿到了如下信息
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
installLocation, verifiers, signatures, coreApp, multiArch);
其中这两个packageSplit.first, packageSplit.second对于一般的apk 都是 null, 是没有拆分的,这些信息都是从manifest 文件里面parse 出来的,最后返回的 是return new PackageLite(codePath, baseApk, splitNames, splitCodePaths);
其中codepath就是 /system/app/helloworld 这个目录, baseapk就是上面的 apklite, 另外splitNames, splitCodePaths 都是null, 这里parseapklite就讲完了。
然后我们看 final Package pkg = parseBaseApk(baseApk, assets, flags); 这里里面对四大组件的详细 解析, 最后会走到这个函数
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
这里我不多讲, 会解析manefest里面的很多东西, 主要包括权限, 四大组件等信息,
最后解析application里面四大组件的地方再这里
private boolean parseBaseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
基本的位置在下面
String tagName = parser.getName();
if (tagName.equals(“activity”)) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a); } else if (tagName.equals("receiver")) { Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.receivers.add(a); } else if (tagName.equals("service")) { Service s = parseService(owner, res, parser, attrs, flags, outError); if (s == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.services.add(s); } else if (tagName.equals("provider")) { Provider p = parseProvider(owner, res, parser, attrs, flags, outError); if (p == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.providers.add(p); }
这里这四个过程就是分别解析manifest里面 四大组件, 然后加到我们的package对象里面对应的四个list里面去。记录这些信息。
这样子解析manefest的大致过程就说完了。
- android 5.0后对于apk 跑32 64 的逻辑
- android 5.0后对于apk 跑32 64 的逻辑
- android 5.0后对于apk 跑32 64 的逻辑
- android 对于apk签名汇总
- android 对于apk签名汇总
- android 对于apk签名汇总
- android 对于apk签名汇总
- Android 系统安装 apk 时解压 so 的逻辑问题
- Android Studio生成签名后的APK
- android 对于apk签名汇总 收藏
- Android APK系列4-------Android编译APK后的系统结构
- Android APK系列4-------Android编译APK后的系统结构
- Android APK系列4-------Android编译APK后的系统结构
- android手机root后的安全问题 (一)植入apk
- Android APK下载后变成ZIP的解决办法
- Android 设置安装后界面显示的apk名
- android apk异常卸载后无法安装的解决办法
- Android apk 签名后程序无法安装的问题
- TextView如何显示丰富的文本
- 利用URLRewriter重写url地址
- 网络:配置 Apache 服务器
- Logistic回归总结
- 设计模式---工厂模式
- android 5.0后对于apk 跑32 64 的逻辑
- linux文件权限管理
- 使用android:layout_weight属性消除视图中的空白
- java堆与栈内存概念的个人理解
- Ui_Spinner
- rabbitmq 综合资源整合帖子
- Ubuntu Redis3.0集群测试
- 【OpenCV】IplImag、HImage相互转换
- Ubuntu快捷键