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.

(callinheritproduct,(SRC_TARGET_DIR)/product/core_64_bit.mk)
(callinheritproduct,(SRC_TARGET_DIR)/product/aosp_base.mk)
$(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.ro.hardware.rcimport/init.{ro.zygote}.rc
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的大致过程就说完了。

0 0